AES_ENCRYPT不适合存密码,因其是可逆加密、无salt、密钥易泄露且设计目标错位;应改用应用层带salt的单向哈希(如Argon2或bcrypt)存储密码哈希值。

MySQL 的 AES_ENCRYPT 不适合存密码,强行用会埋下权限、密钥、合规三重隐患。
为什么不能用 AES_ENCRYPT 存密码
它本质是可逆加密,只要拿到密钥(哪怕硬编码在应用里),就能调 AES_DECRYPT 完全还原明文。而密码场景必须“不可逆”——这是安全底线。另外,MySQL 默认不校验密钥长度,AES_ENCRYPT('pwd', 'key') 用短密钥会静默补零,导致加解密不一致;更麻烦的是,密钥一旦泄露或轮换,所有旧密码无法迁移,只能强制重置。
- 不是加密强度不够,而是设计目标错位:它为字段级机密数据(如身份证号)服务,不是为密码验证设计
- MySQL 没有内置 salt 支持,重复密码会生成相同密文,容易被彩虹表攻击
- 应用层若把密钥写死在 SQL 里(比如
INSERT ... AES_ENCRYPT(?, 'mykey123')),等于把密钥暴露给所有能查日志或抓包的人
该用什么替代 AES_ENCRYPT
用带 salt 的单向哈希,在应用层完成。MySQL 本身只存哈希值,不参与计算。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- PHP 推荐
password_hash($pwd, PASSWORD_ARGON2ID)(需 PHP ≥7.2)或password_hash($pwd, PASSWORD_DEFAULT) - Python 推荐
passlib.hash.argon2.using(rounds=4).hash(pwd)或bcrypt.gensalt() - Node.js 推荐
bcrypt.hash(pwd, 12)(cost=12 是当前较稳妥的平衡点) - 哈希结果直接存 MySQL
VARCHAR(255)字段,别用BINARY或TEXT—— 长度固定且含标识头
如果硬要保留 AES 加密(非密码场景)
仅限加密敏感但需还原的字段,比如用户邮箱、手机号,并且密钥必须脱离数据库和代码。
- 密钥绝不能写进 SQL 或配置文件,用环境变量传入应用,再由应用调用
AES_ENCRYPT;MySQL 自身不持有密钥 - 密钥长度必须是 16/24/32 字节,用
LENGTH('yourkey')确认,否则 MySQL 会静默截断或补零 - 模式固定为
ecb(MySQL 5.7+ 默认)不安全,建议显式指定AES_ENCRYPT(data, key, 'aes-256-cbc')并自己管理 IV - 注意字符集:如果字段是
utf8mb4,加密前先用CONVERT(data USING latin1),否则中文可能因多字节导致解密乱码
真正难的不是选函数,而是决定“谁来管密钥、谁有权解密、密钥轮换时旧数据怎么过渡”。这些不在 SQL 里,而在你的部署流程和权限模型里。










