mysql 8.0双密码切换必须用alter user ... retain current password启动、discard old password收尾;set password仅覆盖主密码并清空辅助密码,不支持双密码机制。

MySQL 8.0 的双密码平滑切换不是靠 SET PASSWORD,而是必须用 ALTER USER ... IDENTIFIED BY ... RETAIN CURRENT PASSWORD 启动,再用 ALTER USER ... DISCARD OLD PASSWORD 收尾——漏掉任一环节或顺序颠倒,都会导致旧连接断开、新密码不生效或辅助密码残留。
为什么 SET PASSWORD 不能用于双密码切换
SET PASSWORD 语句在 MySQL 8.0 中完全不支持双密码机制。它只会覆盖主密码,且无条件清空辅助密码(如果存在)。常见错误现象包括:
- 执行
SET PASSWORD FOR 'u'@'h' = 'new'后,旧密码立即失效,正在运行的应用连接被拒绝 - 脚本里混用
SET PASSWORD和RETAIN CURRENT PASSWORD,结果语法报错ERROR 1064 (42000)—— 因为两者根本不能共存 - 误以为“只要密码设了两次就有双密码”,实际只是反复覆盖主密码,辅助密码从未被创建
根本原因:双密码是账户元数据层面的状态机,只有 ALTER USER 的 RETAIN CURRENT PASSWORD 子句才会触发 mysql.user 表中 password_reuse_history 和认证插件内部的双凭证标记。
RETAIN CURRENT PASSWORD 执行前必须确认的三件事
该语句看似简单,但失败率高,主要卡在前置条件上:
- 账户当前密码不能为空:
SELECT authentication_string FROM mysql.user WHERE user = 'u' AND host = 'h'返回值不能是NULL或空字符串,否则报错ERROR 3031 (HY000): Cannot retain current password for account with empty password - 不能在从库上直接执行:主库执行后,必须等所有从库复制完成(
Seconds_Behind_Master = 0),否则部分节点只认新密码、部分只认旧密码,应用随机报Access denied - 认证插件不能变更:执行时若同时指定
IDENTIFIED WITH caching_sha2_password,会报错ERROR 3894 (HY000): Current password cannot be retained ... because authentication plugin is being changed—— 双密码只允许在同插件下切换密码
DISCARD OLD PASSWORD 不是自动发生的
很多人以为改十次密码后,最老那次就自动过期了。事实相反:只要没显式执行 DISCARD OLD PASSWORD,最早那次被 RETAIN CURRENT PASSWORD 保留下来的密码就一直有效。这带来两个风险:
- 安全审计时发现账户仍能用半年前的密码登录,误判为漏洞
- 某次误操作执行了
ALTER USER ... IDENTIFIED BY 'x'(没带RETAIN),结果把主密码改成x,但辅助密码仍是最初那个——等于凭空多出一个长期有效的弱密码 - 清理必须逐账户执行:
ALTER USER 'u'@'h' DISCARD OLD PASSWORD,不支持通配符或批量操作
真正容易被忽略的是:这个语句本身不校验当前连接是否使用主密码。哪怕你正用辅助密码连着,也能成功执行——执行完立刻踢掉所有用辅助密码的新连接请求,但已有连接不受影响(直到超时或主动断开)。











