PASSWORD_LOCK_TIME仅对caching_sha2_password或mysql_native_password插件生效,单位为天;MySQL 5.7.17前不支持该参数,8.0.19+才稳定支持account_locked状态及自动重置。

CREATE USER 里设置 PASSWORD_LOCK_TIME 不起作用?先确认插件类型
直接在 CREATE USER 语句里写 PASSWORD_LOCK_TIME 却发现账号从不被锁,大概率是认证插件不匹配。这个参数只对 caching_sha2_password 或 mysql_native_password 生效,其他插件(比如 sha256_password、auth_socket)完全忽略它。
检查当前用户用的什么插件:SELECT user, host, plugin FROM mysql.user WHERE user = 'u';
新建用户时必须显式指定插件:CREATE USER 'api'@'%' IDENTIFIED WITH caching_sha2_password BY 'pwd' FAILED_LOGIN_ATTEMPTS 3 PASSWORD_LOCK_TIME 0.00694;
已有用户改密码+策略时也得连插件一起改:ALTER USER 'api'@'%' IDENTIFIED WITH caching_sha2_password BY 'newpwd' FAILED_LOGIN_ATTEMPTS 3 PASSWORD_LOCK_TIME 0.00694;
常见错误:只写 FAILED_LOGIN_ATTEMPTS 3,漏掉 PASSWORD_LOCK_TIME —— MySQL 直接当没这回事,account_locked 永远是 N。
PASSWORD_LOCK_TIME 的单位不是秒,是「天」
想锁 10 分钟?别写 10 或 600,要换算成天:
10 分钟 = 10 ÷ (24 × 60) ≈ 0.00694
1 小时 = 0.04167
24 小时 = 1
PASSWORD_LOCK_TIME 0 表示永久锁定,不是“不锁定”——账号不会自动恢复,必须由管理员手动执行 ALTER USER 'u'@'%' ACCOUNT UNLOCK;。生产环境慎用 0,尤其不能用于 root 或关键业务账号。
锁定期满后也不会自动解锁:必须有一次**成功登录**,才会重置失败计数并清除 account_locked = 'Y' 状态。连续失败 3 次被锁 1 天,第 2 天第一次尝试仍输错,计数继续累加,锁定时间从这次失败重新算起。
MySQL 5.7 和 8.0+ 的行为差异很关键
FAILED_LOGIN_ATTEMPTS 和 PASSWORD_LOCK_TIME 在 MySQL 5.7.6+ 初步支持,但 5.7.17 之前版本根本不认这个语法;真正稳定支持自动重置、状态持久化、account_locked 字段可见,要等到 MySQL 8.0.19+。
在 5.7 中查不到 account_locked 字段,只能靠日志或 SELECT * FROM mysql.user 看 password_last_changed 间接推断;而 8.0+ 可以直接:SELECT user, host, account_locked, password_locking_status FROM mysql.user WHERE user = 'u';
如果用的是 MySQL 5.7 且版本低于 5.7.17,这条路走不通,得退回到应用层控制或改用 max_connect_errors 配合 FLUSH HOSTS。
别把 max_connect_errors 和账户锁定混为一谈
max_connect_errors 是另一个机制:它按客户端 IP 统计连接失败次数(默认 100),超限后该 IP 下所有用户都被拒绝访问,错误提示仍是 Access denied for user,但和 account_locked 无关。它不看用户名,只看来源 IP,也不受 PASSWORD_LOCK_TIME 影响。
排查是否触发了这个限制:SHOW VARIABLES LIKE 'max_connect_errors';SELECT host, user FROM mysql.user WHERE account_locked = 'Y';(仅 8.0+ 有效)
临时解封某个 IP:FLUSH HOSTS;(全局生效,重启后恢复)
MySQL 8.0.22+ 支持更精准的:RESET CONNECTION FOR 'user'@'host';(需 SUPER 权限)
真正防暴力破解,得组合使用:应用层做登录失败频控(如 5 分钟内最多 5 次),数据库层用 FAILED_LOGIN_ATTEMPTS + PASSWORD_LOCK_TIME 做兜底,再配合 max_connect_errors 防 IP 级爆破。


















