MySQL 8.0双密码轮换必须手动执行ALTER USER ... RETAIN CURRENT PASSWORD和DISCARD OLD PASSWORD,且RETAIN CURRENT PASSWORD要求会话必须用旧密码认证、目标用户自行操作、旧密码未过期,否则报错ER_CANT_RETAIN_CURRENT_PASSWORD。

MySQL 8.0 不支持“自动”双密码轮换,RETAIN CURRENT PASSWORD 和 DISCARD OLD PASSWORD 必须手动执行,且有严格前提条件——不是配个参数就生效,而是靠 DBA 精确控制时机和会话状态。
执行 RETAIN CURRENT PASSWORD 前必须满足的条件
这条语句不是随便在任意连接里都能跑通的。它要求当前会话**必须是用旧密码成功认证后建立的**,否则直接报错 ER_CANT_RETAIN_CURRENT_PASSWORD。
- 不能用新密码登录后再执行——哪怕你刚设了新密码,也得先退出,再用旧密码重连
- 不能用 root 或其他高权限账号代为执行——必须由目标用户自己用旧凭据登录后操作
- 如果用户启用了
PASSWORD EXPIRE,旧密码可能已失效,需先用新密码登录并重置过期状态,但此时又无法触发双密码共存 - 连接池场景下容易误判:应用可能复用旧连接(仍持旧密码),但新连接请求已走新密码,导致你误以为“切换完成”
ALTER USER ... IDENTIFIED BY ... RETAIN CURRENT PASSWORD 的实际效果
它不会“并列设置两个密码”,而是明确划分主/辅角色:新密码成为主密码(后续所有 ALTER USER 默认基于它更新),旧密码降级为辅助密码(仅用于已有连接重认证)。
- 新发起的连接:可用主密码或辅助密码登录,无优先级差异(服务端不区分)
- 已有活跃连接:不受影响,继续使用原认证凭证(哪怕那个凭证是旧密码)
- 主密码可被再次修改,但每次修改都需重新
RETAIN CURRENT PASSWORD才能保留上一轮的“旧旧密码” - 辅助密码不能用于触发新的双密码流程——只有主密码具备这个能力
为什么不能直接查到某条连接用了哪个密码
MySQL 服务端不记录、也不暴露“本次连接使用的具体密码值或其哈希标识”,performance_schema.threads 和 information_schema.PROCESSLIST 中的 USER 字段只显示用户名,不反映认证依据。
MySQL 数据库管理技能,能够通过自然语言查询和管理数据库,支持 SELECT/INSERT/UPDATE/DELETE、表管理、备份恢复等操作。当用户提及 MySQL、数据库查询、建表或数据备份时使用此技能。
- 你无法通过 SQL 查询确认某个
root@10.0.1.5连接究竟是用主密码还是辅助密码建立的 - 验证过渡是否完成,只能靠外部手段:比如日志埋点(应用层记录连接时用的密码 hash)、连接池配置审计、或强制滚动重启应用来切断旧连接
- 宽限期设太短(如 1 小时)风险极高——Java 应用的 HikariCP 默认连接空闲超时是 10 分钟,但最大生命周期可达 30 分钟,加上 DNS 缓存、NAT 超时等,真实残留可能远超预期
DISCARD OLD PASSWORD 的不可逆性与检查盲区
一旦执行,辅助密码立即从 mysql.user 表中清除,且无日志记录具体删的是哪一段哈希值(authentication_string 字段只存主密码)。
- 执行前无法通过 SQL 预判是否还有旧密码连接存活——你看到的
PROCESSLIST是快照,不是实时流 - 没有“预检模式”:MySQL 不提供类似
SHOW OLD PASSWORD USAGE的诊断命令 - 若清理后仍有旧密码连接尝试重连(比如长连接断开后自动重试),会直接返回
Access denied for user,而错误日志里不会说明是“旧密码被丢弃”,只会记认证失败 - 补救成本高:必须立刻回退到上一步,重新执行
RETAIN CURRENT PASSWORD,但此时旧密码明文很可能已丢失
真正难的不是语法,是判断“什么时候该执行 DISCARD OLD PASSWORD”。它依赖对应用连接行为的完整理解,而不是数据库自身的反馈能力。










