mysql 8.0密码过期策略需三者协同:alter user控制账户级过期(唯一生效方式),default_password_lifetime仅影响新用户,默认0(永不过期),password_history与password_reuse_interval须配合validate_password插件防重用。

直接说结论:MySQL 8.0 的密码过期和轮换不是“配个参数就自动转起来”的机制,它由三块互不替代的逻辑拼成——ALTER USER 控制单个账户生命周期、default_password_lifetime 只管新建用户默认值、password_history 和 password_reuse_interval 负责防重用。漏掉任何一块,策略就形同虚设。
ALTER USER 是唯一真正生效的过期设置方式
所有其他操作(SET PASSWORD、UPDATE mysql.user、mysqladmin password)都不更新 password_last_changed 或触发过期校验逻辑,哪怕你看到 password_expired = 'Y',也不代表登录时会被拦住。
-
ALTER USER 'app'@'%' PASSWORD EXPIRE INTERVAL 90 DAY:从当前password_last_changed时间起算 90 天后强制重置 -
ALTER USER 'backup'@'localhost' PASSWORD EXPIRE NEVER:显式禁用,注意不是PASSWORD EXPIRE DEFAULT(后者会继承全局值,容易误判) -
ALTER USER 'root'@'localhost' PASSWORD EXPIRE:立即过期,下次登录报ERROR 1820 (HY000) - 必须严格匹配
user@host,'root'@'localhost'和'root'@'%'是两个独立账户,查不到或执行报ERROR 1396 (HY000)就说明 host 不对 - 执行后无需
FLUSH PRIVILEGES,也无需重启 MySQL
default_password_lifetime 只影响新用户,老用户一个都不管
设了 default_password_lifetime = 90 后发现 root、app_user 还是没过期?完全正常。这个变量只对后续 CREATE USER 或未显式指定 PASSWORD EXPIRE 的 ALTER USER 生效。
- 永久生效:在
/etc/my.cnf的[mysqld]段加default_password_lifetime = 90,然后重启 mysqld - 临时测试:用
SET PERSIST default_password_lifetime = 90(写入mysqld-auto.cnf,重启不丢),但别在生产高峰期干这事 - 验证是否加载成功:必须执行
SELECT @@global.default_password_lifetime,返回90才算数;返回0表示永不过期,NULL等效于0 - 已有用户要补策略:得自己查表生成语句,比如:
SELECT CONCAT('ALTER USER ''', user, '''@''', host, ''' PASSWORD EXPIRE INTERVAL 90 DAY;') FROM mysql.user WHERE password_last_changed IS NOT NULL;
password_history + password_reuse_interval 必须配 validate_password 才能防“换汤不换药”
只设 90 天过期,用户把 p@ss123 改成 p@ss124 再改回 p@ss123 就绕过去了。真正拦住这种行为的是 password_history 和 password_reuse_interval,但它们依赖 validate_password 插件/组件启用。
- 必须用
SET PERSIST password_history = 5和SET PERSIST password_reuse_interval = 365设置,单位都是“天” - 检查是否生效:
SELECT @@global.password_history, @@global.password_reuse_interval - 这两个参数对已存在的旧密码不追溯,只从第一次用
ALTER USER IDENTIFIED BY改密开始记录历史 -
SET PASSWORD语句已被弃用(8.0.19+),且不触发历史校验;必须用ALTER USER ... IDENTIFIED BY才行 - 如果
validate_password没加载,设置会静默失败——先确认:SELECT * FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'validate_password';或查组件表mysql.component
过期后用户能做什么?别指望连接池自动处理
密码过期 ≠ 账号锁定。用户仍可建立 TCP 连接,但几乎不能执行任何业务语句,连 SELECT 1 都会报 ERROR 1820,除非先执行 ALTER USER USER() IDENTIFIED BY 'newpass'。
- 允许的操作仅限:
SET NAMES utf8mb4、SET autocommit = 1这类纯会话级命令 - Java 应用用 HikariCP 等连接池时,必须确认是否支持自动重认证;否则连接池缓存的旧凭证会持续失败,引发雪崩
- 监控脚本里建议定期查:
SELECT user, host, password_last_changed, TIMESTAMPADD(DAY, @@default_password_lifetime, password_last_changed) AS expires_at FROM mysql.user WHERE @@default_password_lifetime > 0 AND password_last_changed IS NOT NULL AND TIMESTAMPADD(DAY, @@default_password_lifetime, password_last_changed) - 别信
password_expired = 'Y'就代表已超期——它只是被手动设为过期的状态快照,真实超期靠password_last_changed + password_lifetime计算
最常被忽略的一点:MySQL 8.0 原生不提供“过期前提醒”功能,所谓 7 天预警、邮件通知、控制台弹窗,全得靠外部脚本或监控系统实现。别在 my.cnf 里翻 password_expiration_warning_days——那是误导性文档残留,8.0 并未实现该变量。











