结论:Access denied 错误90%因密码错误或Host不匹配,MySQL认证时先严格比对User、Host、plugin三者,Host不一致则跳过密码校验;常见于localhost与127.0.0.1混淆、caching_sha2_password插件不兼容、或mysql.user表中存在多条root记录导致匹配错位。

直接说结论:这个错误 90% 是密码输错或 Host 字段不匹配,不是权限没开全、也不是服务没起来。
为什么输对密码还报 Access denied for user 'root'@'localhost'?
MySQL 认证时会严格比对三件事:用户名、密码、Host(即连接来源的主机名/IP)。哪怕密码完全正确,只要当前连接请求的 Host 和 mysql.user 表里那条记录的 Host 值不一致,就直接拒绝——连密码校验这步都不会走。
常见错觉场景:
- 你在命令行用
mysql -u root -h 127.0.0.1 -p连,但表里只有'root'@'localhost'——127.0.0.1≠localhost(Unix socket 和 TCP 是两套路径) - 你用 DBeaver 或 Navicat 连,客户端默认走 TCP,即使填了
localhost,实际解析成127.0.0.1,结果匹配不到'root'@'localhost' - MySQL 8.0 默认创建用户时用的是
caching_sha2_password插件,而老客户端(如某些版本 phpMyAdmin、旧版 MySQL Workbench)只认mysql_native_password,插件不兼容也会报这个错,且不提示具体原因
怎么快速确认是密码错还是 Host 不匹配?
别猜,直接查表。先用已有权限账号(比如另一个管理员账号)登录后执行:
SELECT User, Host, authentication_string, plugin FROM mysql.user WHERE User = 'root';
重点关注三列:
-
Host:你当前连接用的是localhost、127.0.0.1还是%?必须和你实际连接方式一致 -
plugin:如果是caching_sha2_password,而你用的是老客户端,大概率要换插件 -
authentication_string:空值或明显不是哈希串(比如是明文或*...开头),说明密码没设对或字段写错了
如果连这个查询都进不去,说明你手头根本没有可用账号,得走跳过权限表流程(见下一条)。
对设计或页面进行 WCAG 2.1 AA 无障碍审计。触发关键词:“audit accessibility”、 “check a11y”、 “is this accessible?” 或在审查设计时使用。
忘记密码或没可用账号时,必须用 skip-grant-tables
这是唯一能绕过认证强制改配置的办法,但操作有风险:期间所有用户都能无密码访问数据库,务必确保环境封闭。
关键步骤(Linux/macOS):
- 停服务:
sudo systemctl stop mysql - 加参数启动:
sudo mysqld_safe --skip-grant-tables &(注意后面有&,后台运行) - 此时可直接
mysql -u root进去(不用-p) - 立刻切库:
USE mysql; - 改密码+插件(MySQL 8.0 推荐):
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_new_password'; - 刷新:
FLUSH PRIVILEGES; - 退出,再
sudo systemctl restart mysql
Windows 用户注意:my.ini 的 [mysqld] 段落里加 skip-grant-tables 后必须完整重启服务,不能只 kill 进程;改完记得删掉这行再重启,否则永远不校验密码。
容易被忽略的点:bind-address 和防火墙不是主因,但会干扰验证
很多人一看到连不上就去改 bind-address = 0.0.0.0 或关防火墙,其实对 'root'@'localhost' 这种本地连接完全无效——localhost 走的是 Unix socket,压根不经过网络栈。
真正该检查的是:
- 你执行
mysql -u root -p时,MySQL 客户端到底连的是 socket 还是 TCP?加-h 127.0.0.1强制走 TCP,加-S /var/run/mysqld/mysqld.sock强制走 socket,结果可能完全不同 -
mysql.user表里有没有重复的root用户?比如同时存在'root'@'localhost'和'root'@'%',而密码不同,MySQL 会按匹配优先级选一条,你改的那条可能根本没生效 - 某些 Docker 镜像或一键安装包会预置多个 root 用户,Host 字段可能是容器名、IP 或
host.docker.internal,不是你想当然的localhost

















