account lock用于人工立即停用账号,需指定完整账号如'u'@'192.168.1.100',执行后新连接即拒,不影响已有连接,验证须实测登录;failed_login_attempts与password_lock_time必须成对设置、依赖validate_password插件及caching_sha2_password认证,缺一不可,否则静默失效。

MySQL 中“锁定账号”不是单一操作,而是分场景:人工停用用 ACCOUNT LOCK,防暴力破解则必须配 FAILED_LOGIN_ATTEMPTS + PASSWORD_LOCK_TIME,两者互不替代,混用还会失效。
怎么用 ACCOUNT LOCK 立即停用一个账号
这是最直接的开关式禁用,适合员工离职、测试下线等明确需人工干预的场景。
- 必须指定完整账号格式,比如
'u'@'192.168.1.100',只写'u'会报错ERROR 3167 (HY000) - 执行后立即生效,无需
FLUSH PRIVILEGES,但已存在的连接(如应用长连接池)不受影响,只拦新连接 - 验证是否真锁住,不能看
account_locked字段——它仍显示N,得用新客户端实测:mysql -u u -p -h your-host,输任意密码都应返回Access denied for user 'u'@'%' (using password: YES) - 解锁只能靠
ALTER USER 'u'@'host' ACCOUNT UNLOCK,GRANT/REVOKE权限不影响锁定状态
为什么 FAILED_LOGIN_ATTEMPTS 设了却没锁住
这个机制默认不生效,缺一不可的条件太多,常见失效全是配置漏项。
-
validate_password插件必须处于ACTIVE状态,查SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'validate_password';未启用时,FAILED_LOGIN_ATTEMPTS完全被忽略 - 用户认证插件必须是
caching_sha2_password(推荐)或mysql_native_password;若为auth_socket,该策略彻底无效 -
FAILED_LOGIN_ATTEMPTS和PASSWORD_LOCK_TIME必须同时设置,单独设任一参数都静默失败 -
PASSWORD_LOCK_TIME单位是「天」,锁 1 小时要写0.04167,写0是永久锁定,不是关闭锁定
MySQL 5.7 或更低版本怎么办
这些版本压根不支持 FAILED_LOGIN_ATTEMPTS,max_connect_errors 不是账号级锁定,别硬套。
-
max_connect_errors控制的是「同一 IP 的连接错误次数」,触发后封的是 IP,不是账号;NAT 环境下容易误伤正常用户 - 无法通过 SQL 实现真正的账号锁定,只能退而求其次:用
REVOKE收回所有权限 +FLUSH PRIVILEGES,但这不是锁定,只是让登录后无法执行任何操作 - 生产环境更可靠的做法是外挂
fail2ban,解析 MySQL 错误日志里的Access denied记录,动态封禁攻击 IP
ACCOUNT LOCK 和自动锁定能一起用吗
能共存,但行为优先级固定:只要 ACCOUNT LOCK 生效,FAILED_LOGIN_ATTEMPTS 就完全不触发。
- 例如一个用户同时设了
ACCOUNT LOCK和FAILED_LOGIN_ATTEMPTS 3,那么输错密码第 1 次就会被拒,失败计数器不会累加,account_locked字段也始终为N - 查状态时,
account_locked = 'Y'只表示由FAILED_LOGIN_ATTEMPTS自动触发的锁定;ACCOUNT LOCK不改这个字段,也不写入日志提示Too many failed login attempts - 生产建议分策略:核心运维账号用
ACCOUNT LOCK人工管控,应用连接账号用FAILED_LOGIN_ATTEMPTS防爆破
真正容易被忽略的点是 host 匹配精度和认证插件类型——'u'@'%' 锁不住从 'u'@'10.0.1.5' 连进来的请求,而 plugin = 'auth_socket' 的账号再怎么设失败次数也没用。验证永远要走真实连接,别信查询结果。











