直接aes_encrypt('abc','key')存null,是因为密钥长度非16/24/32字节、未匹配加密模式与iv、字段类型不支持二进制或字符集转换污染;安全做法是hex加密结果存varchar,解密前unhex还原,并显式指定一致的密钥、iv和模式。

为什么直接 AES_ENCRYPT('abc', 'key') 总是存 NULL?
这不是函数失效,而是 MySQL 在密钥长度、模式参数、字段类型三者不匹配时静默返回 NULL,不报错也不提醒。最常见组合错误是:key 长度不是 16/24/32 字节(比如用 'mykey' 这种 5 字节字符串),或显式指定 'AES-256-CBC' 却没传 init_vector 参数,或把二进制密文直接插进 VARCHAR 字段导致字符集污染。
建表和字段类型怎么选才不踩坑?
别硬上 VARBINARY 或 BLOB——虽然文档说“必须”,但实际操作中更稳的路径是:用 HEX() 把密文转成十六进制字符串,再存进 VARCHAR(512) 或 TEXT。这样绕开所有字符集转换、截断、乱码问题。
- 加密列定义示例:
email_enc VARCHAR(512),配套存 IV 的列:email_iv VARCHAR(32) - 不要复用 IV:每条记录生成独立 IV,推荐用
UNHEX('000102030405060708090a0b0c0d0e0f')这类 16 字节二进制值(HEX 后正好 32 字符) - 密钥不能硬编码:用会话变量
@key或从配置表读取,避免在 SQL 里写死'MySecretKey1234567890123456'
插入和查询时的正确调用链是什么?
加密和解密不是对称的“套函数”操作,而是一串不可跳过的编码还原步骤。漏掉任何一环,AES_DECRYPT() 就返回空或 NULL。
- 插入时必须:先加密 → 再
HEX()→ 最后存字符串:HEX(AES_ENCRYPT('user@ex.com', @key, 'AES-256-CBC', @iv)) - 查询解密时必须:先
UNHEX()还原密文 → 再AES_DECRYPT()→ 最后显式转码:CONVERT(AES_DECRYPT(UNHEX(email_enc), @key, 'AES-256-CBC', UNHEX(email_iv)) USING utf8mb4) - 如果加密的是纯数字或非 UTF-8 数据(如银行卡号),改用
CAST(AES_DECRYPT(...) AS CHAR)更安全
带盐加密能不能只靠 SQL 实现?
可以,但 MySQL 没有内置加盐函数,得手动拼接。关键是盐必须随记录存储、每次独立生成,否则等于没加。
- 生成盐建议用
SUBSTR(SHA2(RAND(), 256), 1, 16)或UUID(),存进单独字段如salt VARCHAR(36) - 动态密钥构造:
CONCAT(salt, @static_key),再喂给AES_ENCRYPT() - 解密时必须查出该行的
salt,拼出完全一致的密钥,否则AES_DECRYPT()必然返回NULL - 注意:盐本身不保密,但绝不能全局复用;IV 和盐是两回事,别混用











