VillageSQL is a drop-in replacement for MySQL with extensions.
All examples in this guide work on VillageSQL. Install Now →
RAND() generates pseudo-random numbers for things like shuffling query results. It isn’t cryptographically secure, which matters when you’re generating tokens, salts, or nonces. RANDOM_BYTES() fills that gap, and VillageSQL’s vsql_crypto extension adds gen_random_bytes() and gen_random_uuid() as part of a unified crypto API.
MySQL’s Random Functions
MySQL provides two built-in random functions with very different purposes:RAND() — Returns a pseudo-random float between 0 and 1. Fast and suitable for non-security applications: randomized query results, weighted sampling, random row selection. Not cryptographically secure.
RANDOM_BYTES(n) — Returns n cryptographically secure random bytes as VARBINARY. Available since MySQL 5.6. Use this for tokens, salts, nonces, and keys.
With VillageSQL: gen_random_bytes() and gen_random_uuid()
VillageSQL’svsql_crypto extension adds gen_random_bytes() and gen_random_uuid(), which use OpenSSL’s RAND_bytes() — the same entropy source as RANDOM_BYTES().
digest(), hmac(), or encrypt() from vsql_crypto, keeping all crypto operations in one extension simplifies upgrades and auditing.
Generating test data
Random functions are useful for seeding test tables:One-time tokens and invite codes
Choosing the Right Function
| Function | Output | Cryptographically secure | Use when |
|---|---|---|---|
RAND() | Float 0–1 | No | Shuffling, sampling, weighted selection |
FLOOR(RAND() * n) | Integer 0–(n-1) | No | Random integers for test data |
RANDOM_BYTES(n) | VARBINARY | Yes | Tokens, nonces, salts — MySQL built-in |
gen_random_bytes(n) | VARBINARY | Yes | Same as RANDOM_BYTES, unified with vsql_crypto API |
gen_random_uuid() | VARCHAR (UUID string) | Yes | UUID v4 as a string — no vsql_uuid required |
RANDOM_BYTES() and gen_random_bytes() are functionally equivalent — both return the same quality of randomness. If you’re already using vsql_crypto, use gen_random_bytes() to keep your crypto surface in one place. If you only need random bytes and nothing else, MySQL’s RANDOM_BYTES() works fine.
If you need a UUID type with sortable variants (v7) and binary storage, use the vsql_uuid extension instead of gen_random_uuid(). See UUIDs in MySQL for the full comparison.
Frequently Asked Questions
Is RAND() safe for generating tokens?
No.RAND() is a pseudo-random number generator seeded from a predictable state. It’s fine for ORDER BY RAND() and similar non-security uses, but tokens generated with RAND() can in theory be predicted. Use RANDOM_BYTES() or gen_random_bytes() for anything security-sensitive.
How many bytes do I need for a secure token?
32 bytes (256 bits) is standard for session tokens and API keys. 16 bytes (128 bits) is the minimum for practical security. Use 32 to be safe.Can I use gen_random_bytes() as a DEFAULT?
No — non-deterministic functions can’t be used in DEFAULT expressions in MySQL. Generate the value in each INSERT statement.What’s the difference between gen_random_uuid() and UUID_V4() from vsql_uuid?
gen_random_uuid() returns a VARCHAR UUID string. UUID_V4() from the vsql_uuid extension returns a native UUID type with 16-byte binary storage. If you’re using UUIDs as primary keys, prefer UUID_V4() or UUID_V7() from vsql_uuid. Use gen_random_uuid() when you need a UUID string and don’t want to install a separate extension.
Troubleshooting
| Problem | Solution |
|---|---|
FUNCTION gen_random_bytes does not exist | Run INSTALL EXTENSION vsql_crypto |
| Tokens appear sequential or predictable | You may be using RAND() instead of gen_random_bytes() |
gen_random_bytes() returns NULL | Check that the argument is a positive integer |
DEFAULT (gen_random_bytes(32)) rejected | MySQL doesn’t allow non-deterministic defaults — generate in each INSERT |

