mysql 8.0.27+才稳定支持双密码轮转,低版本不识别retain current password或旧密码无法认证;新建账号需先设初始密码再执行alter user ... identified by 'new' and retain current password才能生效;验证须查mysql.user表中authentication_string含双哈希且password_reuse_history非null;应用端需主动刷新连接池以确保新旧密码均生效。

MySQL 8.0.27+ 才支持双密码轮转,低版本直接放弃
MySQL 原生的双密码机制(ALTER USER ... IDENTIFIED BY 'pwd1' AND RETAIN CURRENT PASSWORD)从 8.0.27 开始才稳定可用;8.0.26 及更早版本要么不识别 RETAIN CURRENT PASSWORD,要么保留的旧密码无法用于认证(报错 Access denied for user)。确认版本用:SELECT VERSION();。低于 8.0.27 的实例,别折腾——没有兜底方案,硬上等于制造单点故障。
创建账号时必须显式指定旧密码为“当前密码”
双密码不是自动生效的。新建账号后,若想立刻进入轮转状态,不能只设一个密码;必须先用 SET PASSWORD 或 ALTER USER 设定初始密码,再立即执行一次带 RETAIN CURRENT PASSWORD 的修改操作,把当前密码“冻结”为旧密码。否则新密码一设,旧密码就彻底失效。
实操步骤如下:
- 先创建账号并设初始密码:
CREATE USER 'app'@'%' IDENTIFIED BY 'v1_secret'; - 再保留当前密码,并设新密码:
ALTER USER 'app'@'%' IDENTIFIED BY 'v2_secret' AND RETAIN CURRENT PASSWORD; - 此时该账号同时接受
v1_secret和v2_secret登录
验证双密码是否生效:别只测登录,要查 mysql.user 表
仅靠 mysql -uapp -pv1_secret 和 mysql -uapp -pv2_secret 都能连上,不代表轮转逻辑正确——可能只是你误删了旧密码、或根本没触发双密码机制。真正可靠的判断依据是查系统表:
SELECT User, Host, authentication_string, password_last_changed, password_reuse_history FROM mysql.user WHERE User = 'app' \G
关键看两处:
-
authentication_string字段应包含两个哈希值(以逗号分隔),形如$A$...,$A$... -
password_reuse_history若为NULL,说明未启用双密码;只有执行过RETAIN CURRENT PASSWORD后它才会是整数(如1)
应用端切换期间最易踩的坑:连接池未刷新凭证
即使数据库侧双密码已就绪,应用仍可能因复用旧连接而持续失败。这不是 MySQL 的问题,而是客户端行为:
- Java HikariCP / Tomcat JDBC Pool 默认复用连接,不会在连接存活时重新认证
- Python PyMySQL / mysqlclient 建立的长连接,也不会主动重握手
- 解决方式不是等连接超时,而是主动触发连接池“软驱逐”:比如调用
HikariDataSource.evictConnection(),或临时把最大连接数设为 0 再恢复 - 更稳妥的做法是在切新密码前,先让应用灰度重启(滚动发布),确保所有连接重建
双密码本身很轻量,但落地成败几乎全取决于应用层对连接生命周期的理解和控制——这点比语法细节重要得多。











