Skip to main content

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

All examples in this guide work on VillageSQL. Install Now →
Symmetric encryption uses the same key to encrypt and decrypt. It’s the right tool when you need to store sensitive data and retrieve the original value later — unlike hashing, which is one-way. MySQL has AES_ENCRYPT() built in, but it defaults to an insecure mode. This guide covers the trade-offs, how to use AES correctly in MySQL, and when to do encryption in SQL versus the application layer.

How AES Encryption Works in MySQL

MySQL’s AES_ENCRYPT(data, key) uses 128-bit AES with the key derived from the key string. The default mode is ECB — Electronic Codebook — where each 16-byte block is encrypted independently. ECB is deterministic: the same 16-byte input always produces the same 16-byte output. That makes patterns visible in the ciphertext.
CBC mode (Cipher Block Chaining) fixes this by XOR-ing each block with the previous ciphertext before encrypting, using a random initialization vector (IV) for the first block. The same plaintext produces a different ciphertext on every call. MySQL supports CBC, but you have to opt in by changing block_encryption_mode and managing the IV yourself:

With VillageSQL: Automatic CBC and IV Handling

VillageSQL’s vsql_crypto extension provides encrypt() and decrypt(), which use AES-CBC with a random IV generated per call. The IV is prepended to the ciphertext — no extra column, no extra parameter.

AES key sizes

Key length is enforced by the byte count of the key string — shorter keys are zero-padded, longer are truncated. Check LENGTH(@key) if you’re getting unexpected behavior.

Storing encrypted data

encrypt() returns VARBINARY. The stored value includes a 16-byte IV prepended to the ciphertext. Size your column accordingly:

MySQL vs VillageSQL Comparison

When to Encrypt in SQL vs. Application Layer

Encrypting in SQL is convenient but has trade-offs: SQL-layer encryption is useful for protecting data at rest when you trust the application but worry about database-level access (backups, read replicas, compromised DB credentials). Application-layer encryption gives you more control over keys and avoids putting plaintext anywhere near SQL logs. For column-level patterns and schema design, see Encrypting Columns in MySQL.

Frequently Asked Questions

What’s the difference between symmetric and asymmetric encryption?

Symmetric encryption (AES) uses the same key to encrypt and decrypt. It’s fast and well-suited for bulk data. Asymmetric encryption (RSA) uses a public key to encrypt and a private key to decrypt — useful for key exchange, but too slow for bulk data. For storing sensitive column data, symmetric AES is the right choice.

Can I search on an encrypted column?

Not directly. To find rows by an encrypted value, you’d have to decrypt every row — a full table scan. A common workaround: store a keyed hash (HMAC) of the plaintext in a separate indexed column for equality lookups. This leaks that two rows have the same value but not what the value is.

How do I rotate encryption keys?

Read every row, decrypt with the old key, re-encrypt with the new key, write back. For large tables, do this in batches. This is the main operational cost of SQL-layer encryption. Envelope encryption (encrypting the data key with a master key) lets you rotate the master key without touching the data.

Does AES encryption protect against SQL injection?

No. Encryption protects the stored values. SQL injection is an input validation problem — an attacker who can run arbitrary SQL can call decrypt() directly.

Troubleshooting

See also