Generating a random unique 8 character string using MySQL
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
Generating an 8-character string in MySQL is easy. Generating one that is both random-looking and guaranteed unique is the harder part. The key idea is that randomness creates candidates, but uniqueness must still be enforced with a database constraint.
Why RAND() Alone Is Not Enough
If you generate 8-character strings from a limited alphabet, collisions are possible. Even if the chance is low at first, it is never zero. That means a query that only calls RAND() can produce duplicates sooner or later.
So the correct design is:
- generate a candidate string
- store it in a column with a
UNIQUEconstraint - retry when a duplicate-key collision occurs
Without the constraint, you do not actually have uniqueness.
A Simple Candidate Generator
One practical MySQL-friendly candidate source is a shortened UUID() value:
This gives you an 8-character hexadecimal string such as A1F29C4D. It is fast and easy, but truncating to 8 characters means collisions are still theoretically possible. That is why the unique index remains essential.
Enforce Uniqueness in the Table
Start by making the target column unique:
This is the part that actually protects data integrity. Everything else is just candidate generation.
Insert with Retry
One way to handle rare collisions is to try an insert and generate a new candidate if MySQL raises a duplicate-key error. In production systems, that retry loop is often easier to manage in application code, but the same idea can be expressed in SQL logic.
If that fails because of a duplicate key, retry with a new candidate. The database stays the source of truth because the UNIQUE constraint decides whether the string is truly unused.
If You Need a Larger Character Set
Hexadecimal characters only give you 16^8 possibilities. If you want more combinations in the same 8-character length, use a base-36 or base-62 alphabet in application code, or construct a more elaborate SQL expression.
For example, a base-36 style candidate can be approximated like this:
This increases the address space, but it still does not remove the need for a unique constraint and retry logic.
Random-Looking Versus Security-Safe
If the string is just a short public identifier, a random-looking code may be enough. If it protects access, resets passwords, or acts like a secret token, an 8-character code is often too small and RAND()-style generation is not a strong security design.
That distinction matters:
- short code for lookup convenience
- strong token for security
They are not the same requirement.
Application Code Is Often the Best Place
Even though the title asks about MySQL, many teams generate the code in application code and let MySQL enforce uniqueness. That approach usually gives better control over the alphabet, randomness source, retries, and observability.
The database should still keep the UNIQUE constraint. Generating outside the database does not replace that safety net.
Common Pitfalls
- Assuming a random expression automatically guarantees uniqueness.
- Truncating
UUID()and forgetting that collisions are still possible. - Using
RAND()for security-sensitive tokens. - Generating codes without a unique index on the destination column.
- Treating collision handling as impossible just because it is rare.
Summary
- Random generation and guaranteed uniqueness are two different problems.
- Use MySQL to generate a candidate if you want, but enforce uniqueness with a
UNIQUEconstraint. - Shortened
UUID()values are convenient candidate strings. - Retry on duplicate-key collisions instead of pretending collisions cannot happen.
- For security-sensitive use cases, rethink whether an 8-character token is strong enough.
Related reading
- Geographical redundency for database What are the options?
- Get a BigInteger attribute from Cassandra ResultSet
- Get BinData UUID from Mongo as string
- Get boolean from database using Android and SQLite
- Get current AUTO_INCREMENT value for any table
- Get first row for each partition key in Cassandra
- Get Insert Statement for existing row in MySQL
- Get list of all tables in Oracle?

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.