alter user ... retain current password 是开启双密码机制的唯一入口,将新密码设为主密码、当前密码降级为辅助密码,使新旧密码共存且均可登录。

能,MySQL 8.0.14+ 原生支持不停机换密码,关键不是“改”,而是“先共存、再淘汰”——用 RETAIN CURRENT PASSWORD 和 DISCARD OLD PASSWORD 两步完成,旧连接不断,新连接可用新密,全程无业务感知。
ALTER USER ... RETAIN CURRENT PASSWORD 是什么作用?
这是开启双密码机制的唯一入口。它不覆盖旧密码,而是把当前密码“降级”为辅助密码,同时把新密码设为主密码。执行后,账户立刻拥有两个有效密码:主密码(新)和辅助密码(旧),两者都可登录。
常见错误现象:
- 漏写
RETAIN CURRENT PASSWORD—— 导致旧连接立即断开,报错Access denied for user - 对已启用双密码的用户重复执行该语句 —— 辅助密码不会更新,仍为最初那个旧密码,新设的“新密码”会覆盖主密码,但辅助密码不变
- 在 MySQL ERROR 1064 (42000)
使用场景:所有需要灰度切换密码的生产环境,尤其是主从架构、多应用共用账号、配置下发延迟明显的系统。
示例(将 app_user 密码从 old123 换成 new456):
ALTER USER 'app_user'@'%' IDENTIFIED BY 'new456' RETAIN CURRENT PASSWORD;
DISCARD OLD PASSWORD 要什么时候执行?
等所有应用配置完成更新、且确认没有残留连接还在用旧密码时,才执行。它会彻底删除辅助密码,此后仅主密码有效。这步不可逆,执行后旧密码立即失效。
容易踩的坑:
- 过早执行 —— 某个定时任务、监控脚本或离线工具仍用旧密码连接,会突然失败
- 只在部分实例上执行 —— 在主从或分片集群中,必须确保所有目标实例都执行了该语句,否则会出现“有些库能连、有些连不上”的混乱状态
- 没验证就丢弃 —— 建议执行前先查
mysql.user表:SELECT User, Host, authentication_string, password_last_changed FROM mysql.user WHERE User = 'app_user';,确认password_last_changed已更新,且无异常连接活跃
示例:
ALTER USER 'app_user'@'%' DISCARD OLD PASSWORD;
为什么不能直接用 SET PASSWORD 或 UPDATE mysql.user?
MySQL 8.0 彻底废弃了旧式密码修改路径。SET PASSWORD 在 8.0.11+ 已被标记为废弃,8.0.29+ 默认禁用;而直接 UPDATE mysql.user 会导致认证插件元数据不一致,轻则登录失败,重则用户被锁定。
根本原因在于:双密码机制依赖服务端对主/辅密码的显式状态管理,只有 ALTER USER 配合 RETAIN CURRENT PASSWORD 才会正确写入 mysql.user.authentication_string 和内部密码历史结构。其他方式绕过校验逻辑,破坏双密码状态机。
参数差异注意点:
-
ALTER USER ... IDENTIFIED BY 'xxx'单独使用 → 强制覆盖主密码,**清除辅助密码**(即旧密码立刻失效) -
ALTER USER ... IDENTIFIED BY 'xxx' RETAIN CURRENT PASSWORD→ 主密码更新,**保留当前密码为辅助密码** -
ALTER USER ... DISCARD OLD PASSWORD→ **仅删除辅助密码**,不影响主密码及后续登录
如何验证双密码是否生效?
最直接的办法是并行测试:用新密码和旧密码分别尝试连接,都成功才算启用成功。不要只测新密码,否则无法发现“旧连接其实已被切断”的问题。
实操建议:
- 用命令行快速验证(注意加
-p后直接跟密码,避免交互):/usr/bin/mysql -uapp_user -pold123 -h10.0.1.100 -P3306 -e "SELECT 1"/usr/bin/mysql -uapp_user -pnew456 -h10.0.1.100 -P3306 -e "SELECT 1" - 检查当前用户密码状态:
SELECT User, Host, plugin, account_locked, password_reuse_history, password_reuse_time FROM mysql.user WHERE User = 'app_user';(password_reuse_history非 NULL 表明双密码已激活) - 观察错误日志:若某次连接因密码失败被拒绝,日志里会明确写
User app_user@10.0.1.101 failed to authenticate using the password provided in the connection,但不会出现“密码已过期”之类误导信息
真正容易被忽略的是时间窗口控制——辅助密码没有自动过期机制,它一直有效,直到你手动 DISCARD。这意味着如果忘了清理,旧密码就成了长期安全隐患。别依赖“过一阵子自然失效”,必须主动收口。











