alter user retain current password 是唯一启用双密码的入口,其他方式均会覆盖主密码并清空辅助密码;discard old password 必须手动调用,旧密码长期有效;所有操作须在主库执行并确保主从一致及插件匹配。

ALTER USER RETAIN CURRENT PASSWORD 是唯一启用双密码的入口
MySQL 8.0 的双密码不是“设两次密码就自动生效”,而是必须用 ALTER USER ... IDENTIFIED BY ... RETAIN CURRENT PASSWORD 显式触发。其他方式——比如 SET PASSWORD、直接 UPDATE mysql.user、或不带 RETAIN CURRENT PASSWORD 的 ALTER USER——全都不行,只会覆盖主密码并清空辅助密码。
常见错误现象:
- 执行
SET PASSWORD FOR 'u'@'h' = 'new'后旧连接立刻断开 - 脚本里写成
ALTER USER 'u'@'h' IDENTIFIED BY 'new'(漏掉RETAIN CURRENT PASSWORD),结果只是硬切换 - 在从库上直接执行该语句,导致主从节点认证行为不一致,应用随机报
Access denied
实操建议:
- 执行前先确认账户有有效密码:
SELECT authentication_string FROM mysql.user WHERE user = 'u' AND host = 'h',结果不能是NULL或空字符串 - 必须在主库执行,且等所有从库复制完成(
SHOW SLAVE STATUS\G中Seconds_Behind_Master = 0)再推进应用侧变更 - 不能在事务中包裹该语句——
ALTER USER是隐式提交,事务控制无意义
DISCARD OLD PASSWORD 必须手动调用,不会自动清理
双密码共存后,旧密码不会过期、不会被覆盖、也不会随后续改密自动失效。只要没执行 DISCARD OLD PASSWORD,最早那次被 RETAIN CURRENT PASSWORD 保留下来的密码就一直有效——哪怕你又改了五次密码。
这带来两个实际风险:
- 安全审计时发现半年前的密码仍能登录,误判为高危漏洞
- 某次误操作执行了
ALTER USER 'u'@'h' IDENTIFIED BY 'x'(没带RETAIN),结果主密码变成x,但辅助密码仍是最初那个,等于凭空多留了一条长期有效凭证
实操建议:
- 清理动作必须显式执行:
ALTER USER 'u'@'h' DISCARD OLD PASSWORD - 执行前务必确认:所有应用连接已使用新密码建连(可查
performance_schema.threads的PROCESSLIST_USER字段,或结合应用日志) - 不要依赖“改完就自动丢弃”的假设;把它当作一个需人工/脚本核验后才触发的安全操作
为什么 SET PASSWORD 会破坏双密码状态
SET PASSWORD 在 MySQL 8.0 中完全不感知双密码机制。它只做一件事:把输入密码写入 authentication_string 字段,并强制清空辅助密码字段(如果存在)。这不是兼容性问题,是设计如此。
典型踩坑场景:
- 运维脚本混用旧习惯和新语法,比如先跑
ALTER USER ... RETAIN CURRENT PASSWORD,再跑SET PASSWORD—— 第二步直接废掉双密码 - 用监控工具自动轮询执行密码更新,但底层调用的是
SET PASSWORD接口,结果每次都在“假装轮转”,实则反复覆盖主密码 - 误以为
SET PASSWORD支持RETAIN子句,语法报错ERROR 1064 (42000)
实操建议:
- 彻底移除脚本、CI/CD 流程、自动化工具中对
SET PASSWORD的调用 - 所有密码变更逻辑统一走
ALTER USER+ 显式子句判断(RETAIN CURRENT PASSWORD或DISCARD OLD PASSWORD) - 如果必须兼容老系统调用,应在中间层拦截并转换为合规 SQL,而不是放行原始
SET PASSWORD
主从复制与插件一致性是双密码生效的前提
双密码状态存储在 mysql.user 表元数据中,依赖复制机制同步。但有两个关键约束常被忽略:
- 不能在从库上直接执行
ALTER USER ... RETAIN CURRENT PASSWORD—— 从库只接受来自主库的 binlog 事件,自行执行会导致状态不一致 - 执行时不能同时更改认证插件,例如:
ALTER USER 'u'@'h' IDENTIFIED WITH caching_sha2_password BY 'new' RETAIN CURRENT PASSWORD会失败,报错ERROR 3894 (HY000)
实操建议:
- 所有双密码操作严格限定在主库发起,且必须等待
Seconds_Behind_Master = 0后再验证或切流 - 检查用户当前插件:
SELECT plugin FROM mysql.user WHERE user = 'u' AND host = 'h',确保新密码沿用相同插件(如caching_sha2_password) - 若需更换插件,必须分两步:先用
DISCARD OLD PASSWORD清理双密码状态,再单独执行插件变更











