Skip to main content

VillageSQL is a drop-in replacement for MySQL with extensions.

All examples in this guide work on VillageSQL. Install Now →
MySQL has MD5(), SHA1(), and SHA2() built in. They work, but they return hex strings — 64 characters for a SHA-256 hash, when the underlying data is 32 bytes. Storing hashes in binary cuts that in half and is more efficient to index. digest() from VillageSQL’s vsql_crypto extension returns raw binary and gives you a single function for every algorithm.

The MySQL Default: Scattered Functions, Hex Output

MySQL provides three separate functions for hashing:
They work, but the storage is wasteful. SHA2 with 256 bits returns a 64-character VARCHAR — twice the bytes needed, since each byte of hash is encoded as two hex digits. To get binary output you’d write UNHEX(SHA2('hello', 256)), which works but is awkward to type consistently. There’s also no sha224 or sha384 option — you’re limited to what MySQL exposes.

The Standard Workaround: UNHEX + SHA2

For compact binary storage, developers wrap SHA2() in UNHEX():
This gets you compact storage. It’s slightly verbose but it’s the standard approach and works fine for SHA-256 and SHA-512.

With VillageSQL: digest()

VillageSQL’s vsql_crypto extension adds digest(data, algorithm), which returns a VARBINARY hash directly — no UNHEX() wrapper needed.
Use HEX() when you need a readable string for logging or display:

Supported algorithms

Don’t use MD5 or SHA-1 for new applications — both have known collision vulnerabilities. SHA-256 is the practical default for most uses. For password storage specifically, digest() is the wrong tool — see Password Hashing in MySQL for crypt() and gen_salt().

When to Use Each Approach

For new projects on VillageSQL, digest() is the cleaner choice. For existing MySQL-only applications, UNHEX(SHA2()) is equally correct.

Frequently Asked Questions

What’s the difference between digest() and SHA2()?

SHA2('hello', 256) returns a 64-character hex string. digest('hello', 'sha256') returns a 32-byte VARBINARY. They compute the same hash — the difference is encoding. Binary storage is more compact and faster to index.

Can I use digest() to detect duplicate rows?

Yes. Store digest(content, 'sha256') in an indexed column, then query WHERE sha256 = digest(incoming_content, 'sha256'). This is a common pattern for deduplicating uploaded files, detecting changed records, or building content-addressable lookups.

Is digest() safe for passwords?

No. digest() is a fast hash — it computes in microseconds. Password hashing requires a slow, iterated algorithm. Use crypt() and gen_salt() from the same extension. See Password Hashing in MySQL.

Does digest() support HMAC?

No — digest() is a plain hash with no key. For keyed authentication codes, use hmac(). See HMAC Signatures in MySQL.

Troubleshooting

See also