必须用alter user ... identified by ... retain current password实现双密码轮换,因set password会直接覆盖主密码并清空辅助密码,导致旧连接重连失败;且该语句需满足账户有非空密码、插件为caching_sha2_password、版本≥8.0.14三个前提。

必须用 ALTER USER ... IDENTIFIED BY ... RETAIN CURRENT PASSWORD,其他任何方式都会导致旧连接中断或双密码失效。
为什么 SET PASSWORD 不能用于双密码轮换
SET PASSWORD 和双密码机制完全不兼容——它不是“改密”,而是“覆盖+清空”:
- 执行
SET PASSWORD FOR 'u'@'h' = 'new'后,authentication_string字段立即更新为新密码哈希,且辅助密码被无条件清空 - 已建立的连接不会断,但下次重连(如连接池回收、应用重启)全部失败,报
ERROR 1045 (28000) - 脚本里混写
SET PASSWORD和RETAIN CURRENT PASSWORD,MySQL 直接报ERROR 1064 (42000)语法错误 - 它不检查当前密码是否为空、不校验插件类型、也不验证主从状态,失败时无明确提示
ALTER USER ... RETAIN CURRENT PASSWORD 的三个硬性前提
这条语句不是“写了就能跑”,缺一不可,否则直接报错:
-
ERROR 3031 (HY000):账户当前没有有效密码,authentication_string为NULL或空字符串。解决办法:先执行ALTER USER 'u'@'h' IDENTIFIED BY 'old'设一个主密码 - 认证插件不是
caching_sha2_password。查一下:SELECT plugin FROM mysql.user WHERE user = 'u' AND host = 'h';不匹配就先执行ALTER USER 'u'@'h' IDENTIFIED WITH caching_sha2_password BY 'xxx' - MySQL 版本低于
8.0.14。确认命令:SHOW VARIABLES LIKE 'version'。旧版本该语法根本不存在
主从环境下执行顺序与验证要点
在复制架构中,双密码切换不是主库一执行就完事:
- 必须在主库执行,且执行后立刻查
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>;再查mysql.user表,authentication_string字段值不变(仍是旧密码哈希),说明辅助密码已保留
DISCARD OLD PASSWORD 不是自动发生的,漏掉就等于留后门
双密码不会随改密次数增加而自动过期。只要没显式执行 DISCARD OLD PASSWORD,最早那次被 RETAIN CURRENT PASSWORD 保留下来的密码就一直有效:
- 安全审计发现半年前的密码还能登录?大概率就是漏了这一步
- 误执行一次不带
RETAIN CURRENT PASSWORD的ALTER USER ... IDENTIFIED BY 'x',会导致主密码变成x,但辅助密码仍是最初那个,等于凭空多留一个长期有效口令 -
DISCARD OLD PASSWORD不接受参数,也不支持批量操作,每个账户都得单独执行
最容易被忽略的是:双密码状态完全依赖 mysql.user 表里的元数据标记,而不是密码哈希本身。你查不到“两个密码”,只能靠行为验证——新旧密码都能连上,才是真生效。











