default_password_lifetime仅影响新用户,老用户必须用ALTER USER单独设置;设为90后root等旧账号仍不过期属正常,因该参数不追溯已有账户,且SET PASSWORD、UPDATE mysql.user等操作均无效。

default_password_lifetime 只管新用户,老用户一个都不生效
设了 default_password_lifetime = 90 后发现 root、app_user 还是没过期?正常。这个变量只影响后续 CREATE USER 或未显式指定 PASSWORD EXPIRE 的 ALTER USER 操作,对已有账户完全无效。
常见误操作:
- 改完配置文件或执行 SET PERSIST default_password_lifetime = 90 就以为万事大吉
- 用 SET PASSWORD FOR 'u'@'h' = 'xxx' 更新密码后期待策略自动继承——该语句在 8.0.19+ 已弃用,且不更新 password_last_changed 字段,倒计时不会重置
- 查当前值必须用
SELECT @@global.default_password_lifetime;,返回0表示永不过期,NULL效果等同于0 - 生产环境建议设为
0(禁用全局过期),再对关键账号逐个用ALTER USER显式控制,避免批量失效风险 - 别信
PASSWORD EXPIRE DEFAULT——它不是“不过期”,而是继承全局值,容易误判
ALTER USER 是唯一真正生效的方式
UPDATE mysql.user SET password_expired = 'Y' 或直接改 password_last_changed 字段?完全无效。MySQL 8.0 的过期逻辑只响应 ALTER USER 语句触发的元数据变更,包括内部策略标记和时间戳同步。
真正可用的语法只有这几种:
-
ALTER USER 'root'@'localhost' PASSWORD EXPIRE INTERVAL 90 DAY;—— 90 天后强制重置 -
ALTER USER 'app'@'%' PASSWORD EXPIRE;—— 立即过期,适合临时账号 -
ALTER USER 'backup'@'localhost' PASSWORD EXPIRE NEVER;—— 显式禁用,慎用
注意:'root'@'localhost' 和 'root'@'%' 是两个独立账户,host 必须完全匹配;执行前先确认账号存在,否则报错 ERROR 1396 (HY000)。
密码重用限制必须配 validate_password 插件
只设过期天数,用户把 p@ss123 改成 p@ss124 再改回 p@ss123 就绕过去了。要防这种“换汤不换药”,得靠 password_history 和 password_reuse_interval,但它们依赖 validate_password 插件。
漏掉任一环节都会静默失效:
- 先装插件:
INSTALL PLUGIN validate_password SONAME 'validate_password.so';,然后SHOW PLUGINS确认状态为ACTIVE - 再设参数(顺序不能错):
SET PERSIST password_history = 5;+SET PERSIST password_reuse_interval = 365; - 重设密码必须用
ALTER USER ... IDENTIFIED BY,SET PASSWORD不触发校验
这两个参数对已存在的旧密码不追溯,只从设置后第一次 ALTER USER 开始生效。
验证是否真生效,别只看表字段
查 mysql.user 表看到 password_expired = 'Y' 就以为策略起作用?不一定。真实拦截需同时满足三个条件:
- @@default_password_lifetime > 0
- 用户没有 ALTER USER 权限(有权限可跳过重置)
- 连接未使用 --init-command 自动执行改密语句
最简验证方式:
用目标账号登录后立刻执行一条非 SET 语句,比如 SELECT 1;。只有返回明确的 ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement. 才算真正落地。
线上服务账号(如应用连接池用的 app_user)一旦过期,连接池通常不会自动重连+重认证,会卡死在 ERROR 1820,这是最容易被忽略的故障点。


















