ALTER USER ... ACCOUNT LOCK 未生效大概率因 MySQL 版本低于 5.7.6,该语法自此版本才引入;低版本会报错或静默忽略,需用 SELECT VERSION() 确认,并改用删密码等替代方案。

ALTER USER ... ACCOUNT LOCK 为什么没生效?
直接执行 ALTER USER 'user1'@'%' ACCOUNT LOCK; 后,用户仍能登录,大概率是因为 MySQL 版本低于 5.7.6 —— 这个语法在 5.7.6 才正式引入,低版本会报错 ERROR 1064 (42000) 或静默忽略。确认版本用 SELECT VERSION();,低于该版本得换方案(比如删密码或改认证插件)。
锁账户后连接被拒的典型错误信息
账户锁定成功后,用户再尝试登录会收到明确提示:ERROR 3118 (HY000): Access denied for user 'user1'@'192.168.1.100'. Account is locked. 注意这个错误码 3118 是关键标识。如果看到的是 ERROR 1045 (28000) 或其他权限类错误,说明根本没锁住,或者 host 匹配不一致(比如你锁的是 'user1'@'localhost',但用户从 'user1'@'192.168.1.100' 连)。
ACCOUNT LOCK 和 PASSWORD EXPIRE 的区别
两者都阻止登录,但机制不同:
-
ACCOUNT LOCK是硬性拦截,认证流程一开始就被拒绝,不校验密码 -
PASSWORD EXPIRE仍允许连接,但强制用户在首次登录后立刻改密(需客户端支持),对自动化脚本、连接池等场景不友好 - 锁账户不影响
mysql.user表里其他字段(比如权限),而DROP USER会连权限一并清除 - 锁住的账户仍可被
GRANT/REVOKE修改权限,不影响权限管理逻辑
批量锁定异常账户的实操要点
别手写一堆 ALTER USER,用查询生成语句更安全:
SELECT CONCAT('ALTER USER ''', user, '''@''', host, ''' ACCOUNT LOCK;')
FROM mysql.user
WHERE account_locked = 'N'
AND user NOT IN ('root', 'mysql.sys')
AND password_last_changed < DATE_SUB(NOW(), INTERVAL 90 DAY);
注意三点:
- 查
mysql.user表前先FLUSH PRIVILEGES;确保元数据最新 -
account_locked字段在 8.0.12+ 才有,5.7 只能靠password_expired或自定义标记 - 生成的语句要人工核对 host 模式(
%vslocalhost),避免误锁运维账号
锁完记得验证:用被锁账户试连,确认返回 ERROR 3118;同时检查 SELECT user, host, account_locked FROM mysql.user; 确认字段已更新为 Y。最容易漏的是跨主机匹配和版本兼容性——这两处一错,锁就形同虚设。


















