90%的access denied错误源于host匹配失败、认证插件不兼容或grant option缺失;需先执行select user,host from mysql.user where user='root'确认报错host是否存在,再按需创建对应账号、alter user指定mysql_native_password插件并赋予grant option权限。

直接说结论:90% 的 Access denied for user 错误,不是密码错了,而是 host 匹配失败、认证插件不兼容、或 GRANT OPTION 缺失——三者叠加时尤其难排查。
查清楚到底是哪个 'root'@'xxx' 在报错
MySQL 把 'root'@'localhost' 和 'root'@'127.0.0.1' 当作两个完全独立的账号,哪怕密码一样也不互通。错误信息里写的 host,就是你要对准的目标。
- 运行
SELECT User, Host FROM mysql.user WHERE User = 'root';,看输出里有没有和错误里一模一样的Host值 - 如果只看到
root@localhost,但你是用mysql -h 127.0.0.1 -u root -p连的,那就必然失败 - 补一个对应 host 的账号:
CREATE USER 'root'@'127.0.0.1' IDENTIFIED WITH mysql_native_password BY '你的密码'; - 别漏掉
GRANT ALL PRIVILEGES ON *.* TO 'root'@'127.0.0.1' WITH GRANT OPTION;和FLUSH PRIVILEGES;
MySQL 5.7+ 必须指定认证插件
从 5.7 开始,默认插件是 caching_sha2_password,但很多客户端(尤其是老版本 PHP、Python MySQLdb、某些监控工具)只认 mysql_native_password。密码没错也会报 Access denied。
对设计或页面进行 WCAG 2.1 AA 无障碍审计。触发关键词:“audit accessibility”、 “check a11y”、 “is this accessible?” 或在审查设计时使用。
- 进库后先确认当前插件:
SELECT plugin FROM mysql.user WHERE User = 'root' AND Host = 'localhost'; - 如果不是
mysql_native_password,强制改掉:ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的密码'; - 注意:不能用
UPDATE mysql.user SET authentication_string = ...—— 字段已废弃,且不会生效 - 改完立刻执行
FLUSH PRIVILEGES;,否则新设置不加载
GRANT 失败?先看自己有没有 GRANT OPTION
你用 root 登录,不代表你能给别人授权。MySQL 8.0+ 默认不给 root@localhost 自带 WITH GRANT OPTION,所以 GRANT 命令会静默失败或报 Access denied。
- 查自己权限:
SHOW GRANTS FOR CURRENT_USER();,重点看输出里有没有WITH GRANT OPTION - 没有就补上:
GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION; - MySQL 8.0+ 不允许在
GRANT语句里写IDENTIFIED BY,必须拆成CREATE USER+GRANT两步 - 细粒度权限(比如库级、表级)不全存在
mysql.user表里,SELECT * FROM mysql.user看不到Select_priv: Y≠ 权限没给
跳过权限启动后忘了关 --skip-grant-tables
临时用 --skip-grant-tables 重置密码没问题,但如果重启服务时配置文件里还留着这行,或者 systemd 启动脚本里硬编码了它,MySQL 就永远不校验密码——接着你会发现所有用户都能连,但新建用户始终无法登录,FLUSH PRIVILEGES 也无效。
- 检查是否启用:
SELECT @@skip_grant_tables;,返回 1 就说明还在跳过模式 - 查配置文件:
grep -r "skip-grant-tables" /etc/mysql/ /etc/my.cnf - 查 systemd 启动参数:
systemctl cat mysqld | grep ExecStart,确认没硬编码该参数 - 删掉配置后必须重启服务,不能只 reload
最易被忽略的一点:bind-address = 127.0.0.1 是默认值,但它会拒绝所有非本地 IPv4 连接;而 skip-networking 一旦开启,连 127.0.0.1 都不通——这两个配置常被当成“安全加固”随手加,结果成了权限错误的隐形推手。










