Developer Lab · MySQL
Generate UUID in MySQL
MySQL has built-in UUID support since 4.1.2. UUID() generates a v1 UUID. MySQL 8.0+ adds UUID_TO_BIN() for efficient BINARY(16) storage and BIN_TO_UUID() for retrieval.
Quick Reference
| Function | Version | MySQL | Use Case |
|---|---|---|---|
| UUID() | v1 | 5.x+ | Quick generation - returns VARCHAR(36) |
| UUID_TO_BIN(UUID(), 1) | v1 (reordered) | 8.0+ | Efficient storage - BINARY(16), time-bit reordered |
| BIN_TO_UUID(id, 1) | any | 8.0+ | Convert BINARY(16) back to UUID string |
| DEFAULT (UUID_TO_BIN(UUID(), 1)) | v1 | 8.0+ | Auto-generate UUID on INSERT |
Primary Implementation
-- ── Generate a UUID ──────────────────────────────────────────
SELECT UUID();
-- → 6ccd780c-baba-1026-9564-0040f4311e29 (v1, VARCHAR)
-- ── Best practice: store as BINARY(16) ───────────────────────
-- UUID_TO_BIN(uuid, 1) reorders the time bits for better index locality
-- The second argument (1) enables "swap_flag" - moves the time-high bits
-- to the front, making sequential UUIDs sort correctly in B-tree indexes
CREATE TABLE orders (
id BINARY(16) NOT NULL DEFAULT (UUID_TO_BIN(UUID(), 1)),
customer VARCHAR(100) NOT NULL,
total DECIMAL(10,2) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
-- ── Insert without specifying ID (auto-generated) ────────────
INSERT INTO orders (customer, total) VALUES ('Alice', 99.99);
-- ── Insert with explicit UUID ─────────────────────────────────
INSERT INTO orders (id, customer, total)
VALUES (UUID_TO_BIN(UUID(), 1), 'Bob', 149.99);
-- ── Query - convert BINARY(16) back to UUID string ───────────
SELECT BIN_TO_UUID(id, 1) AS id, customer, total
FROM orders;
-- ── Find by UUID string ───────────────────────────────────────
SELECT BIN_TO_UUID(id, 1) AS id, customer
FROM orders
WHERE id = UUID_TO_BIN('6ccd780c-baba-1026-9564-0040f4311e29', 1);All Approaches
Simple VARCHAR(36) - MySQL 5.x compatible
-- Simple approach - works on MySQL 5.x
-- Downside: VARCHAR(36) uses 36 bytes vs 16 bytes for BINARY(16)
-- Also causes B-tree index fragmentation with random UUIDs
CREATE TABLE users (
id VARCHAR(36) NOT NULL DEFAULT (UUID()),
name VARCHAR(100) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com');
SELECT id, name FROM users;BINARY(16) with swap_flag - MySQL 8.0+ recommended
-- BINARY(16) with swap_flag=1 - best for high-insert-rate tables
-- swap_flag reorders time bits so sequential UUIDs are adjacent in the index
-- This eliminates B-tree page splits and dramatically improves INSERT performance
CREATE TABLE events (
id BINARY(16) NOT NULL DEFAULT (UUID_TO_BIN(UUID(), 1)),
event_type VARCHAR(50) NOT NULL,
payload JSON,
created_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
PRIMARY KEY (id),
INDEX idx_created (created_at)
);
-- Generate UUID in application and pass it in
-- (recommended for idempotent inserts)
INSERT INTO events (id, event_type, payload)
VALUES (UUID_TO_BIN('6ccd780c-baba-1026-9564-0040f4311e29', 1), 'order.created', '{"orderId": 42}');
-- Read back as UUID string
SELECT BIN_TO_UUID(id, 1) AS id, event_type, created_at
FROM events
ORDER BY created_at DESC
LIMIT 10;Stored procedure - generate and return UUID
DELIMITER $$
CREATE PROCEDURE create_order(
IN p_customer VARCHAR(100),
IN p_total DECIMAL(10,2),
OUT p_id VARCHAR(36)
)
BEGIN
SET p_id = UUID();
INSERT INTO orders (id, customer, total)
VALUES (UUID_TO_BIN(p_id, 1), p_customer, p_total);
END$$
DELIMITER ;
-- Call the procedure
CALL create_order('Alice', 99.99, @order_id);
SELECT @order_id AS created_order_id;Common Mistakes
Storing UUIDs as VARCHAR(36) in high-traffic tables
VARCHAR(36) uses 36 bytes per row vs 16 bytes for BINARY(16). More importantly, random UUIDs as primary keys cause B-tree index fragmentation - every INSERT goes to a random page, causing constant page splits and poor cache utilization. Use BINARY(16) with UUID_TO_BIN(UUID(), 1).
Forgetting the swap_flag argument in UUID_TO_BIN()
UUID_TO_BIN(UUID()) without the second argument stores the UUID as-is - random bytes, no time ordering. Use UUID_TO_BIN(UUID(), 1) to reorder the time bits for sequential inserts.
Using UUID() in WHERE clauses without UUID_TO_BIN()
If your id column is BINARY(16), you must convert the string in your WHERE clause: WHERE id = UUID_TO_BIN('...', 1). Comparing a BINARY(16) column to a plain string will not use the index.
How It Works
MySQL's UUID() generates a version 1 UUID - it encodes the current timestamp (100-nanosecond intervals since Oct 15, 1582) plus a random node ID. It is unique across time and space but leaks timing information.
UUID_TO_BIN(uuid, 1) converts the 36-char string to 16 bytes and reorders the time components so that UUIDs generated close together are stored adjacent in the B-tree index - dramatically improving INSERT performance on large tables.
Output Formats
UUID()
6ccd780c-baba-1026-9564-0040f4311e29
UUID_TO_BIN(UUID(), 1)
BINARY(16) - 16 bytes
BIN_TO_UUID(id, 1)
6ccd780c-baba-1026-9564-0040f4311e29
Best Practices, Performance, and Security
Best practices
Use BINARY(16) with UUID_TO_BIN(UUID(), 1) for production tables.
Generate UUIDs in your application layer for idempotent inserts - pass them to MySQL rather than relying on DEFAULT (UUID()).
Always use BIN_TO_UUID(id, 1) in SELECT queries to return human-readable UUIDs.
Performance
BINARY(16) with swap_flag=1 gives near-sequential insert performance - comparable to auto-increment integers. Without the swap flag, random UUIDs cause severe B-tree fragmentation on tables with millions of rows.
Index size: BINARY(16) = 16 bytes vs VARCHAR(36) = 36 bytes - 55% smaller indexes, better cache utilization.
Security
MySQL's UUID() generates a v1 UUID - it encodes the server's MAC address and timestamp. This leaks server identity and timing information.
For security-sensitive IDs (session tokens, API keys), generate UUID v4 in your application layer using a CSPRNG and pass it to MySQL - don't rely on UUID().
Installation
Built-in functions
UUID()MySQL 5.x+UUID_TO_BIN()MySQL 8.0+BIN_TO_UUID()MySQL 8.0+DEFAULT (UUID_TO_BIN(...))MySQL 8.0.13+Frequently Asked Questions
How do I generate a UUID in MySQL?
MySQL's built-in UUID() function returns a version 1 (time- and MAC-address-based) UUID, not a random v4. It has been available since MySQL 4.1.2. For index-friendly storage on MySQL 8.0+, wrap it with UUID_TO_BIN(UUID(), 1) and store the result in BINARY(16). MySQL has no native v4 or v7 generator, so produce those in your application layer.
Is UUID() cryptographically secure?
No. MySQL's UUID() returns a version 1 UUID derived from the timestamp and the server's MAC address, not from a CSPRNG, so it is predictable and leaks server identity. It is not suitable for session tokens, API keys, or other security-sensitive identifiers - generate a v4 UUID with a CSPRNG in your application layer for those.
What is the difference between UUID v4 and v7 in MySQL?
Note that MySQL's UUID() is v1 (time + MAC), not v4. A v4 UUID is fully random and not sortable, while v7 embeds a millisecond timestamp for chronological sorting (RFC 9562). MySQL has no native v4 or v7 function, so generate those in your application and store them as BINARY(16); use v7 for database primary keys at scale.
Do I need to install a package for UUID generation in MySQL?
No package is needed for MySQL's built-in UUID(), which returns a v1 UUID. MySQL cannot generate v4 or v7 natively, so for those you generate the UUID in your application layer and insert it.
How do I validate a UUID string in MySQL?
Use the platform's UUID parse/validation function, or test against the RFC 4122 regex: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i. Always validate external input at API boundaries.
Should I use UUIDs as database primary keys in MySQL applications?
UUIDs work well as primary keys for distributed systems. Prefer native UUID/BINARY(16) column types over VARCHAR(36). For very large tables, consider UUID v7 for better B-tree insert locality.
Can I generate UUIDs in MySQL without a network connection?
Yes. UUID generation uses local OS entropy sources and does not require network access. Each call is independent and thread-safe on modern platforms.
What output formats are available in MySQL?
The standard hyphenated lowercase string (36 chars) is the default. Most APIs also support 32-char hex (no hyphens) and 16-byte binary formats. Use string format for APIs and binary for database storage.
What RFC standards apply to MySQL UUID generation?
Version 4 UUIDs follow RFC 4122. UUID v7 follows RFC 9562 (May 2024). Ensure your chosen method produces compliant version and variant bits.
When should I avoid UUID v1?
Avoid UUID v1 in security-sensitive contexts - it embeds the server MAC address and timestamp. Note that MySQL's UUID() is itself v1, so when you need unpredictability, generate a v4 in your application layer instead of relying on UUID().
Key definitions
- UUID
- 128-bit universally unique identifier, usually shown as 36 hex characters with hyphens.
- CSPRNG
- Cryptographically secure pseudo-random number generator - the entropy source behind secure UUID generation.
- RFC 4122
- IETF standard defining UUID versions 1 through 5. Version 4 is random.
- RFC 9562
- IETF standard adding UUID versions 6, 7, and 8. Version 7 is time-ordered.