For twenty years the answer was v4, because the alternative broadcast your network card's address to anyone holding the id. RFC 9562 landed in May 2024 with versions 6, 7 and 8, and it changed the recommendation for one specific and very common case: when the UUID is going to be a primary key.
What Is Actually in a UUID
128 bits, written as 32 hex digits in a 8-4-4-4-12 pattern. Six of those bits are not yours: four say which version this is, two say which variant of the specification it follows.
You can read both by eye. The first digit of the third group is the version, so in f81d4fae-7dec-11d0-a765-00a0c91e6bf6 the 1 after the dash makes it a v1. The first digit of the fourth group encodes the variant, and for every UUID you will meet in practice it is 8, 9, a or b, meaning the RFC's own variant. Anything else is a Microsoft GUID from before the standard settled, or not a UUID at all.
That leaves 122 bits to carry meaning, and what a version does with them is the entire difference between the versions.
Every Version, and What It Puts in Those Bits
Versions 2 and 8 are omitted: v2 is a DCE Security variant almost nothing implements, and v8 is a blank slate for vendor-defined layouts.
| Version | Contents | Reach for it when |
|---|---|---|
| v1 | 60-bit timestamp, clock sequence, node id | You are joining a system that already uses it. Otherwise no |
| v3 | MD5 of a namespace plus a name | Something already depends on MD5. Use v5 instead |
| v4 | 122 random bits | The default. Anything that does not need ordering |
| v5 | SHA-1 of a namespace plus a name | The id must be reproducible from a name, on any machine |
| v6 | v1's fields, timestamp reordered to sort | You are migrating an existing v1 system and want ordering |
| v7 | 48-bit Unix ms timestamp, then 74 random bits | The id is a database key, or anything indexed or sorted |
Why a Random Key Costs You
A database index is a B-tree, and a B-tree is kept in sorted order on disk. Insert a row with a key that sorts after everything already there and the write lands in the rightmost page, which is already in memory because the last insert touched it too. That is the sequential case, and it is close to free.
Insert a random key and it lands wherever it happens to sort, which is a page the database probably has to read from disk first. Once that page fills, it splits in two, leaving both halves half-empty. Do this a few million times and the index has grown well past the size the same data would occupy in insertion order, while the pages your working set needs no longer fit in the buffer pool.
MySQL's InnoDB makes this worse than most, because its tables are physically clustered on the primary key: the whole row lives in the leaf page, so a random primary key scatters the table itself, not just an index. PostgreSQL stores rows in a heap and keeps the index separate, so it suffers the index fragmentation without the table fragmentation.
None of this is an argument against UUIDs. It is an argument against *random* UUIDs in the one position where sort order maps to physical layout.
The UUID that identified a virus author
Version 1 put the machine's MAC address in the last 48 bits, on the reasoning that a globally unique network card guarantees a globally unique id. It also guarantees a globally unique fingerprint. When the Melissa macro virus spread in March 1999, investigators pulled the GUIDs Microsoft Word had embedded in the document and used them, along with other evidence, to tie the file to David L. Smith, who was arrested within a week. RFC 9562 section 6.10 now says to use random bits with the multicast bit set instead, which is what any browser-based generator has to do anyway, since no web page can read a MAC address.
What v7 Actually Does
The layout is deliberately boring: 48 bits of Unix timestamp in milliseconds, then the four version bits, then 12 bits, then the two variant bits, then 62 more bits of randomness. The timestamp is first, so comparing two v7 UUIDs as bytes, or as text, compares them by creation time.
48 bits of milliseconds runs out around the year 10889, which is not a problem anyone reading this will have.
The subtlety is what happens inside a single millisecond. A thousand ids created in the same millisecond share the same leading 48 bits and are then ordered by pure randomness, which is exactly the fragmentation you switched away from v4 to avoid, just at a smaller scale. RFC 9562 section 6.2 answers this by allowing those 12 bits after the version to be a counter that increments within the millisecond, and a generator that skips it is only approximately sortable. This site's generator uses the counter, so a batch of a hundred comes out strictly increasing rather than merely grouped.
One thing v7 gives up: the creation time of every record is now readable by anyone holding the id. Usually that is fine or even useful. If your ids are exposed to users and the timing is sensitive, that is the trade you are making.
Generate a UUID in any version
v4, v7, v1, v6, name-based v3 and v5, plus the nil and max constants.
Decisions That Follow
Once the version is settled, the rest of the choices tend to get made badly by default.
Store 16 bytes, not 36 characters
PostgreSQL has a native `uuid` type that occupies 16 bytes. MySQL does not, so use `BINARY(16)` rather than `CHAR(36)`, which more than doubles the storage and makes every index comparison longer.
Do not reorder v4 bytes to fake sorting
The old MySQL trick of shuffling a v1's timestamp fields into sortable order is exactly what v6 standardised. Use v6 or v7 rather than a custom byte swap nobody else can read.
Only v4 is unguessable
A v7 is mostly timestamp, and a v1 is timestamp plus a node id that never changes. Neither is a secret. If the id doubles as an access token, it has to be v4, and even then a purpose-built token is the better answer.
Pick v5 over v3
They differ only in the hash, and MD5 has no reason to be in new code. Neither is a security decision, since both truncate to 122 bits, but v5 is the one the RFC points at.
Keep the hyphens unless something forbids them
The canonical form has them, every parser expects them, and stripping them saves four bytes in a text column you should not be using anyway.
A UUID Is Not a Password
RFC 9562 is direct about this in its security considerations: do not assume a UUID is hard to guess. The specification covers versions whose contents are almost entirely predictable, and a system that treats "has the UUID" as "is authorised" is relying on a property only one version happens to have.
The exception, stated precisely, is a v4 from a cryptographically secure source. 122 random bits is more entropy than a 20-character password, and the browser's crypto.randomUUID() is backed by the same generator as the rest of Web Crypto. That is genuinely unguessable.
What it is not is revocable, rotatable or scoped. An unguessable URL is still a URL, and it will end up in a referrer header, a proxy log and someone's chat history. Use it for an unlisted share link where the consequence of a leak is proportionate. Do not use it where you would otherwise have asked for a login.
Frequently Asked Questions
Related Tools
Keep Reading
Password Strength: Why Length Beats Complexity Rules
NIST withdrew the advice about symbols and 90-day expiry, and the arithmetic explains why. One extra character is worth more than every symbol on the keyboard.
SHA-256 Explained: What Hashes Guarantee and What They Do Not
Three properties make a hash cryptographic, and each one supports a different use. Why SHA-256 is the wrong tool for storing passwords.
MD5 in 2026: Broken for Security, Still Useful for Checksums
Collisions have been practical since 2004 and forged a Microsoft certificate in 2012. Which of MD5's remaining uses that break actually affects.
Base64 Is Not Encryption: What It Does and Why It Exists
Three bytes become four characters, which is where the 33 percent size increase and the trailing equals signs come from. And why it hides nothing.