mysql 8.0双密码机制仅在alter user ... identified by ... retain current password成功执行后建立,需满足账户有非空密码、插件为caching_sha2_password、版本≥8.0.14;否则报error 3031或3894,且set password会立即清空辅助密码,discard old password必须显式执行。

MySQL 8.0 的双密码机制不是“配置出来就自动生效”的功能,它只在 ALTER USER ... IDENTIFIED BY ... RETAIN CURRENT PASSWORD 成功执行后才建立,且必须满足三个硬性前提:账户已有非空密码、认证插件为 caching_sha2_password、MySQL 版本 ≥ 8.0.14。不满足任一条件,语句直接报错,不会进入“半生效”状态。
为什么 ALTER USER ... RETAIN CURRENT PASSWORD 总是报 ERROR 3031 或 ERROR 3894
这两个错误不是语法问题,而是账户状态或语义冲突的明确提示:
-
ERROR 3031 (HY000):账户当前没有有效密码,authentication_string字段为NULL或空字符串。常见于刚CREATE USER但没设密码,或用SET PASSWORD清过密码的账号。解决办法:先执行ALTER USER 'u'@'h' IDENTIFIED BY 'old'设一个主密码,再执行带RETAIN CURRENT PASSWORD的语句 -
ERROR 3894 (HY000):语句中混用了IDENTIFIED WITH,例如ALTER USER 'u'@'h' IDENTIFIED WITH caching_sha2_password BY 'new' RETAIN CURRENT PASSWORD。双密码只允许在同一认证插件下切换,不能借改密顺便换插件 - 从库上执行也会失败,且不报“请在主库执行”,而是静默拒绝。必须先确认
SHOW SLAVE STATUS\G中Seconds_Behind_Master = 0
SET PASSWORD 会立刻破坏双密码状态
SET PASSWORD 和双密码机制完全无关,它是 MySQL 5.7 时代的遗留语法,在 8.0 中仅用于兼容。一旦执行,旧密码立即失效,辅助密码被清空:
-
SET PASSWORD FOR 'u'@'h' = 'new'后,所有持旧密码的连接无法重连(已建立的连接不会断,但下次认证失败) - 哪怕前一秒刚用
RETAIN CURRENT PASSWORD建好双密码,这一条SET PASSWORD就让辅助密码消失 - 脚本里混用两者,MySQL 直接报
ERROR 1064 (42000)语法错误——它们根本不能共存
如何验证双密码是否真生效
不能只看语句执行成功,必须做三件事验证:
- 分别用新密码和旧密码各连一次:
mysql -u u -p'old' -h host和mysql -u u -p'new' -h host,都应成功返回mysql> - 查
mysql.user表:SELECT user, host, authentication_string FROM mysql.user WHERE user = 'u' AND host = 'h';,authentication_string字段值应仍是旧密码的哈希(说明旧密码被保留为辅助密码,而非被覆盖) - 检查插件:
SELECT plugin FROM mysql.user WHERE user = 'u' AND host = 'h';,结果必须是caching_sha2_password;如果不是,需先执行ALTER USER 'u'@'h' IDENTIFIED WITH caching_sha2_password BY 'xxx'
最容易被忽略的是 DISCARD OLD PASSWORD 必须显式执行——它不会随时间、次数或密码轮换自动触发。漏掉这一步,半年前的密码依然能登录,审计时就是高危项。而且它不支持参数、不能批量,每个账户都得单独执行一次。











