必须用高权限账号执行alter user 'root'@'localhost' identified by '新密码' account unlock,同步解除锁定与密码过期状态,并确认plugin兼容性;仅输对密码无法登录。

不能靠输对密码登录,必须先解除 account_locked = 'Y' 状态,且通常要同步处理密码过期和认证插件兼容性问题。
确认 root 账户确实被锁(不是密码错或服务没起)
报错 ERROR 3118 (HY000): Access denied for user 'root'@'localhost' (account is locked) 是明确信号;如果只报 Access denied 但没提 “account is locked”,可能是插件不兼容或密码过期。先用已有高权限账号(如另一个未锁的管理员)连上,执行:
SELECT User, Host, account_locked, password_expired, plugin FROM mysql.user WHERE User = 'root';
重点看三列:account_locked 为 'Y' 才是真锁定;password_expired 为 'Y' 会阻止首次登录;plugin 是 caching_sha2_password 则老客户端可能连不上——这三项常共存,但错误提示只暴露一个。
用 --init-file 安全解锁(推荐生产环境)
比 --skip-grant-tables 更稳妥:不跳过权限系统,只在启动时执行一条 SQL,避免误操作风险。步骤如下:
- 创建临时 SQL 文件,例如
/tmp/unlock-root.sql,内容严格为两行(注意空格和引号):ALTER USER 'root'@'localhost' ACCOUNT UNLOCK; ALTER USER 'root'@'%' ACCOUNT UNLOCK;
- 确保文件可读:
sudo chown mysql:mysql /tmp/unlock-root.sql - 停服务:
sudo systemctl stop mysql - 用 init-file 启动:
sudo mysqld --user=mysql --init-file=/tmp/unlock-root.sql & - 等几秒后检查端口:
sudo ss -tlnp | grep :3306,有输出即成功 - 立刻验证:
mysql -u root -p,应能登录且不再报锁 - 杀掉该临时实例:
sudo kill $(pgrep mysqld),再正常启服务:sudo systemctl start mysql
注意:ACCOUNT UNLOCK 中间必须有空格,写成 ACCOUNTUNLOCK 或 ACCOUNT UNLOK 都会报 ERROR 1064。
登录后必须立刻检查并修复插件与密码状态
解锁只是恢复登录资格,不代表能用旧工具连上。进库后第一件事是查插件:
SELECT User, Host, plugin FROM mysql.user WHERE User = 'root';
若返回 caching_sha2_password,而你用的是 Navicat 旧版、PHP 7.4 mysqli 或某些 shell 脚本,得改回兼容插件:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的新密码'; ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '你的新密码';
同时确认两个字段都为 'N':
SELECT account_locked, password_expired FROM mysql.user WHERE User = 'root' AND Host = 'localhost';
如果 password_expired = 'Y',只执行 ACCOUNT UNLOCK 没用——登录后仍会被强制改密,而被锁用户根本连不进来。所以实际操作中,这两步最好合并:
ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码' ACCOUNT UNLOCK;
为什么不能直接 UPDATE mysql.user + FLUSH PRIVILEGES?
在 --skip-grant-tables 模式下,MySQL 8.0 明确禁用所有权限相关语句:UPDATE mysql.user 和 FLUSH PRIVILEGES 都会报 ERROR 1290 (HY000)。这不是权限不足,是设计限制。更麻烦的是,即使绕过限制强行更新,MySQL 服务进程不会自动感知字段变更,仍可能沿用缓存状态。而 ALTER USER 是唯一被 MySQL 内部识别并触发实时状态刷新的合法途径。
最易忽略的是:账户锁定发生在认证入口,密码过期检查在认证之后,插件协商失败则压根走不到认证逻辑——三层拦截位置不同,排查时漏一层就白忙。











