default_password_lifetime仅对新用户生效,老用户必须用alter user显式设置;设为90后root等旧账号仍不过期属正常,因其不追溯已有账户,且set password等操作无效。

default_password_lifetime 改了就生效?别信
改了 default_password_lifetime 并不会让已有用户突然开始倒计时。它只对「新创建的用户」或「没显式设置过期策略的用户」起作用。老用户仍沿用原来的 password_last_changed 时间戳,而 MySQL 不会主动重写这个字段——哪怕你把全局值从 0 改成 90,那个 2024 年建的账号依然按“永不过期”算,直到它下次改密才更新时间戳。
常见误操作:SET GLOBAL default_password_lifetime = 90 后立刻去测一个老账号,发现登录完全正常,就以为策略失效。其实只是它压根不走这条路。
- 必须用
ALTER USER ... PASSWORD EXPIRE INTERVAL N DAY显式覆盖老用户策略 - 配置文件修改比运行时
SET GLOBAL更可靠:编辑/etc/my.cnf的[mysqld]段,加default_password_lifetime = 90,然后systemctl restart mysqld - 验证是否持久生效:
SHOW VARIABLES LIKE 'default_password_lifetime';,重启后仍返回90才算落地
为什么用户登录时报 ERROR 1820 却查不到过期字段?
ERROR 1820 (HY000): You must reset your password... 是密码真正过期后的拦截动作,但 MySQL 并不提供“剩余天数”这种直观字段。判断依据只有两个:
-
password_expired = 'Y'(显式被设为过期) - 或
password_last_changed IS NOT NULL且TIMESTAMPADD(DAY, @@default_password_lifetime, password_last_changed)
所以查 mysql.user 表时,得手动算:
SELECT user, host, password_last_changed,
TIMESTAMPADD(DAY, @@default_password_lifetime, password_last_changed) AS expires_at
FROM mysql.user
WHERE password_last_changed IS NOT NULL;
注意:password_last_changed 是 UTC 时间,别拿本地时间直接比。
validate_password 插件不装,过期策略形同虚设
光设密码 90 天过期,却允许用户设 '123456' 或 'password',那过期毫无意义——攻击者爆破一次就进来了。MySQL 5.7 的 validate_password 插件必须启用,否则等保二级/三级都通不过。
- 安装命令:
INSTALL PLUGIN validate_password SONAME 'validate_password.so'; - 永久生效要配
my.cnf:plugin-load-add = validate_password.so+validate_password = FORCE_PLUS_PERMANENT - 策略至少设为
MEDIUM:SET GLOBAL validate_password.policy = MEDIUM;,它强制要求大小写字母+数字+特殊字符+最小长度 8 - 测试弱密码:
SET PASSWORD = PASSWORD('abc123');应报ERROR 1819
ALTER USER 设置过期时最容易漏掉的三个细节
给现有用户批量加固时,ALTER USER 看似简单,但以下三点一错,策略就断在最后一环:
- 用
PASSWORD EXPIRE是立即过期,不是“90 天后”,适合应急;日常应统一用PASSWORD EXPIRE INTERVAL 90 DAY -
PASSWORD EXPIRE NEVER才是取消过期,PASSWORD EXPIRE DEFAULT是继承全局值,不是“恢复默认行为” - 执行后当前连接不受影响,用户得断开重连才会触发提示;如果应用用了长连接池,得滚动重启或等连接自然失效
真正落地的密码过期策略,从来不是改一个变量就完事——它必须同时锁住创建入口(default_password_lifetime)、堵住弱口令漏洞(validate_password)、并逐个清理存量账户(ALTER USER)。少任何一环,审计时都会卡在“策略未全覆盖”这一条上。











