Scanning database...
Tools
Articles

No matches found for ""

View All Results
Home Dev Lab mysql
Developer Lab

UUID in MySQL

Production-ready implementation guide with CSPRNG-backed code snippets.



Generate UUID in MySQL

MySQL has built-in UUID support since 5.x. 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

Production Ready
sql snippet — MySQL 8.0+
-- ── 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

sql snippet
-- 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

sql snippet
-- 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

sql snippet
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

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.

Version Requirements

UUID()MySQL 5.x+
UUID_TO_BIN()MySQL 8.0+
BIN_TO_UUID()MySQL 8.0+
DEFAULT (UUID_TO_BIN(...))MySQL 8.0.13+

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().