mysql 8.0+批量设置密码策略必须通过update mysql.user表并flush privileges实现,alter user不支持批量语法;需确保有system_user权限、禁用严格模式、避开password_history等不可直写字段,并执行备份与验证。

MySQL 8.0+ 中用 ALTER USER 批量改密码策略不现实
直接对成百上千用户逐条执行 ALTER USER ... PASSWORD EXPIRE INTERVAL 90 DAY 或 FAILED_LOGIN_ATTEMPTS 5,不仅耗时,还会锁表(尤其在高并发环境),且无法原子化执行——中途出错就得人工回滚。MySQL 原生不支持 ALTER USER 的批量语法,硬写脚本拼 SQL 容易因用户名含特殊字符(如连字符、空格、@)、权限不足或 SQL 模式限制而失败。
真正可行的方案:用 mysql.user 系统表 + UPDATE + FLUSH PRIVILEGES
MySQL 8.0+ 的密码策略参数(如 password_last_changed、password_lifetime、account_locked、failed_login_attempts)实际存储在 mysql.user 表中。只要满足以下条件,就可以安全批量更新:
- 你有
UPDATE权限操作mysql.user表(通常需SYSTEM_USER或root) - 已停用
sql_mode=STRICT_TRANS_TABLES(否则UPDATE可能因字段长度/默认值报错) - 不修改
authentication_string字段本身(避免误重置密码哈希)
示例:将所有非系统用户的密码有效期设为 180 天,并启用失败登录锁定:
UPDATE mysql.user
SET password_lifetime = 180,
failed_login_attempts = 5,
password_lock_time = NULL
WHERE user NOT IN ('mysql.infoschema', 'mysql.session', 'mysql.sys', 'root')
AND host != 'localhost'; -- 排除本地管理账号
FLUSH PRIVILEGES;
必须绕开的坑:password_history 和 password_reuse_interval 不可直接 UPDATE
这两个字段在 mysql.user 表里是 TEXT 类型,但 MySQL 内部用二进制格式序列化密码历史记录,手动写入字符串会破坏校验逻辑,导致用户下次改密时报 ERROR 3032 (HY000): Cannot update password history for user。正确做法只有两种:
- 对单个用户用
ALTER USER ... PASSWORD HISTORY 5逐个设置(适合少量关键账号) - 若需全量统一策略,只能先清空历史(
ALTER USER ... PASSWORD HISTORY 0),再设新值——但注意这会清除所有已有历史记录
没有“批量初始化 password_history”的后门方式,强行 UPDATE 该字段等于给账号埋雷。
执行前必须验证的三件事
别跳过检查,否则可能批量锁死用户账号:
- 确认目标用户当前未被锁:
SELECT user, host, account_locked FROM mysql.user WHERE user IN (...); - 测试单条 UPDATE 是否生效:
UPDATE mysql.user SET password_lifetime = 30 WHERE user = 'testuser' LIMIT 1;,然后FLUSH PRIVILEGES,再用SHOW CREATE USER 'testuser'核对结果 - 备份
mysql.user表:mysqldump --single-transaction mysql user > user_backup.sql(务必加--single-transaction避免锁表)
策略字段生效依赖客户端重新连接,旧连接不会立即感知变化;部分字段(如 password_lock_time)只在下一次登录失败时触发,不能靠查询当前值判断是否“已锁定”。











