ALTER USER ... ACCOUNT LOCK锁定的是认证环节,用户能连接MySQL但身份校验直接失败,返回ERROR 1045;锁定状态存于mysql.user表account_locked字段,值为'Y',须用ALTER USER语句生效,不依赖FLUSH PRIVILEGES。

MySQL账号锁定后连不上,ALTER USER ... ACCOUNT LOCK到底锁了什么
它锁的是认证环节——用户能连上MySQL服务,但身份校验直接失败,返回ERROR 1045 (28000): Access denied for user。不是网络层拦截,也不是权限表失效,而是MySQL在密码比对前就拒绝继续流程。
- 锁定只影响该账号的登录,不影响其他账号,也不影响已存在的连接(比如你用root锁了testuser,testuser当前会话仍可执行命令,直到断开)
- 锁定状态写在
mysql.user表的account_locked字段,值为'Y';手动改这个字段不生效,必须用ALTER USER语句触发内部状态同步 - MySQL 5.7.6+才支持该语法,5.7.5及更早版本无此功能,强行执行会报
ERROR 1064 (42000)
怎么锁定一个账号:别漏掉FLUSH PRIVILEGES?其实不用
ALTER USER 'u1'@'localhost' ACCOUNT LOCK;执行完立刻生效,不需要FLUSH PRIVILEGES。因为账号锁定是独立于权限缓存的运行时状态,MySQL服务端实时读取mysql.user并校验account_locked字段。
- 错误写法:
UPDATE mysql.user SET account_locked='Y' WHERE User='u1';→ 即使更新成功,下次重启或刷新权限后会被覆盖,且不触发内部状态机 - 正确写法必须带主机名:
ALTER USER 'u1'@'%' ACCOUNT LOCK;,不能只写'u1',否则报ERROR 1396 (HY000) - 如果账号不存在,语句直接报错,不会静默忽略
解锁账号时遇到ERROR 3022 (HY000):说明账号被设了密码过期
有时候ALTER USER 'u1'@'localhost' ACCOUNT UNLOCK;失败,提示ERROR 3022 (HY000): Cannot unlock user 'u1'@'localhost' because the password has expired。这不是锁定导致的,而是密码过期策略(password_expired)和账号锁定(account_locked)是两个正交开关。
- 先查状态:
SELECT User,Host,account_locked,password_expired FROM mysql.user WHERE User='u1'; - 如果
password_expired='Y',得先重置密码:ALTER USER 'u1'@'localhost' IDENTIFIED BY 'newpass' PASSWORD EXPIRE NEVER; - 再解锁:
ALTER USER 'u1'@'localhost' ACCOUNT UNLOCK; - 注意:MySQL 8.0默认启用密码历史策略,若新密码太像旧密码,也会报错,需换一个明显不同的
批量锁定/解锁账号的坑:通配符%不能用于ALTER USER
想一键锁掉所有非root账号?不能写ALTER USER '%@%' ACCOUNT LOCK——语法不支持模式匹配,会报ERROR 1396 (HY000)。必须明确指定每个User@Host组合。
- 安全做法是生成SQL语句:
SELECT CONCAT("ALTER USER '",User,"'@'",Host,"' ACCOUNT LOCK;") FROM mysql.user WHERE User NOT IN ('root','mysql.infoschema','mysql.session'); - 复制结果、检查、再执行,避免误锁系统账号
- MySQL 8.0.19+支持角色(ROLE),可把多个账号加入同一角色,再用
SET DEFAULT ROLE控制访问,但角色本身不提供“锁定”能力,只是权限聚合手段
真正容易被忽略的是:账号锁定状态不会随DROP USER自动清除,但DROP USER本身会删掉整行记录;而CREATE USER重建同名账号时,account_locked默认是'N',不是继承之前的状态。所以“锁完再删再建”,等于白锁。










