必须用ALTER USER ... IDENTIFIED BY ... RETAIN CURRENT PASSWORD实现双密码,SET PASSWORD不支持该语法且会清空辅助密码、导致旧密码立即失效;需满足当前密码非空、插件为caching_sha2_password、版本≥8.0.14,主从同步完成后再切换应用,DISCARD OLD PASSWORD须显式执行才能清理辅助密码。

必须用 ALTER USER ... IDENTIFIED BY ... RETAIN CURRENT PASSWORD,其他任何方式都会导致旧连接中断或双密码失效。
为什么 SET PASSWORD 一用就断连
它根本不是为双密码设计的:执行 SET PASSWORD FOR 'u'@'h' = 'new' 后,旧密码立刻无法认证,已建立的连接虽不马上断,但下次重连(比如连接池刷新、应用重启)就报 ERROR 1045 (28000)。更隐蔽的问题是,哪怕前一秒刚建好双密码,这一条 SET PASSWORD 就会清空辅助密码——你查 mysql.user 表看不到变化,但旧密码登录已失败。
常见误操作包括:
- 脚本里混写
SET PASSWORD和RETAIN CURRENT PASSWORD,直接触发ERROR 1064 (42000)语法错误 - 用新密码登录后执行
RETAIN CURRENT PASSWORD,报ER_CANT_RETAIN_CURRENT_PASSWORD - 在从库上执行,不报错但不生效,应用切流后部分节点连不上
ALTER USER ... RETAIN CURRENT PASSWORD 的三个硬性前提
这条语句不是“写了就能跑”,缺一不可,否则必报错:
-
ERROR 3031 (HY000):账户当前没密码,authentication_string是 NULL 或空字符串 → 先执行ALTER USER 'u'@'h' IDENTIFIED BY 'old'设一个主密码 -
ERROR 3894 (HY000):语句里混用了IDENTIFIED WITH,比如IDENTIFIED WITH caching_sha2_password BY 'new' RETAIN CURRENT PASSWORD→ 双密码只允许在同一插件下切换,不能边改密边换插件 - MySQL 版本低于 8.0.14 →
SHOW VARIABLES LIKE 'version'必须确认;插件不是caching_sha2_password→ 查SELECT plugin FROM mysql.user WHERE user = 'u' AND host = 'h',不匹配需先单独改插件
主从环境下的执行顺序和验证要点
主库执行完 ALTER USER 'u'@'h' IDENTIFIED BY 'new' RETAIN CURRENT PASSWORD 并不等于完成。从库没同步完前切应用,会有一批连接因“从库还不认新密码”而失败。
必须按这个顺序走:
- 主库执行后,立刻查
SHOW SLAVE STATUS\G,等所有从库Seconds_Behind_Master = 0再推进 - 不要把该语句包进事务 ——
ALTER USER是隐式提交,事务控制无效 - 验证是否真双活:
mysql -u u -p'old' -h host和mysql -u u -p'new' -h host都应成功;再查mysql.user表,authentication_string字段值不变(仍是旧密码哈希),说明辅助密码已保留
DISCARD OLD PASSWORD 不是自动发生的
双密码不会随改密次数增加而自动过期。只要没显式执行 ALTER USER 'u'@'h' DISCARD OLD PASSWORD,最早那次被 RETAIN CURRENT PASSWORD 保留下来的密码就一直有效——安全审计时发现半年前的密码仍能登录,大概率就是漏掉了这一步。
注意:
-
DISCARD OLD PASSWORD不接受参数,也不支持批量操作,每个账户都得单独执行 - 误执行一次不带
RETAIN CURRENT PASSWORD的ALTER USER ... IDENTIFIED BY 'x',会导致主密码变成x,但辅助密码仍是最初那个,等于凭空多留一个长期有效口令 - 双密码状态完全依赖
mysql.user表里的元数据标记,而不是密码哈希本身;你查不到“两个密码”,只能靠行为验证


















