mysql 8.0密码过期策略需分层实施:default_password_lifetime仅控制新用户默认过期天数(如设为90),对已有用户(含root)完全无效;必须用alter user显式设置各账户的password expire interval或never,才能真正生效。

MySQL 8.0 的密码过期策略不能只靠改 default_password_lifetime 就算完事——它只管新用户,老用户(包括 root)完全不受影响,必须单独用 ALTER USER 设置。
查看当前全局密码过期设置是否生效
别猜配置文件有没有加载成功,直接查运行时值最可靠:
SELECT @@global.default_password_lifetime;
返回 0 表示永不过期;返回正整数(如 90)表示新用户默认 90 天后过期;返回 NULL 效果等同于 0。注意:@@default_password_lifetime 是简写,但生产环境建议显式写 @@global.default_password_lifetime 避免作用域歧义。
永久启用 90 天过期策略(新用户自动继承)
修改配置文件比运行时 SET 更稳妥,尤其对重启后持续生效的场景:
- 编辑
/etc/my.cnf(Linux)或my.ini(Windows),在[mysqld]段下添加:
[mysqld] default_password_lifetime = 90
Windows 下务必确认文件编码是 ANSI 或 GBK,UTF-8 BOM 会导致 MySQL 启动失败并报错 Found option without preceding group。
改完必须重启 MySQL 服务,并再次执行 SELECT @@global.default_password_lifetime; 确认读取的是新值——有时旧缓存会误导你。
安全的随机密码生成器。支持自定义长度、字符类型(大写/小写字母、数字、特殊符号),排除相似字符,批量生成。纯 Python 标准库,无需 API 密钥。
让已有用户(比如 root)也遵守 90 天策略
这是最常被跳过的一步,也是线上出问题的高发点:
-
default_password_lifetime对已存在的用户完全无效,哪怕他们刚改过密码 -
root、admin、backup这些账号,都得手动覆盖 - 执行命令前先确认账号存在且 host 匹配准确,例如
'root'@'localhost'和'root'@'%'是两个不同用户
批量处理老用户没有内置命令,得自己查表+循环:
SELECT CONCAT('ALTER USER ''', user, '''@''', host, ''' PASSWORD EXPIRE INTERVAL 90 DAY;')
FROM mysql.user
WHERE password_expired = 'N' AND password_last_changed IS NOT NULL;
把结果复制出来执行,或者用脚本封装。千万别漏掉 password_last_changed IS NOT NULL 条件,否则可能误操作匿名用户或空密码账户。
用户登录后提示 ERROR 1820 怎么办
这不是连接失败,而是密码已过期或被设为强制重置:
- 能连上,但除
SET、UNLOCK TABLES、SELECT(仅限部分只读上下文)、ALTER USER ... IDENTIFIED BY外,其他语句一律报错 - 用户自己执行:
ALTER USER USER() IDENTIFIED BY 'newpass'; - 管理员代为重置:
ALTER USER 'u1'@'%' IDENTIFIED BY 'newpass' PASSWORD EXPIRE NEVER;(加PASSWORD EXPIRE NEVER才算真正解除过期状态) - 错误做法:
SET PASSWORD FOR 'u1'@'%' = 'newpass';—— 这只会改密,不会清除password_expired = 'Y'标记,下次登录照样卡住
真正落地密码策略,default_password_lifetime 只是起点,ALTER USER 才是必经之路;而最容易被忽略的,就是以为改了全局变量就一劳永逸——其实它连 root 都没管。










