错误根因是MySQL拒绝认证,需检查实际凭证、host权限(localhost≠127.0.0.1)、.env加载状态、MySQL 8+的caching_sha2_password插件兼容性,并用命令行交叉验证。

报错 SQLSTATE[HY000] [1045] Access denied for user 'root'@'localhost' (using password: YES),不是 ThinkPHP 配置写错了,而是 MySQL 明确拒绝了这次认证——它认出了用户名、也收到了密码,但判定不合法。直接看 PDOException 的 message,90% 的问题靠这一句就能锁死根因。
怎么看真实的 1045 错误信息
ThinkPHP 只是把 PDO 抛出的异常原样往上扔,关键线索全在 message 里。别只盯着日志里“数据库连接失败”这句空话,去 runtime/log/ 下翻最新日志,找到带 PDOException 的那一行,复制整条 message:
-
"SQLSTATE[HY000] [1045] Access denied for user 'root'@'localhost' (using password: YES)"→ 用户存在,密码也传了,但 MySQL 不认 -
"... (using password: NO)"→ PHP 实际传的密码是空字符串(''),哪怕配置写了密码,也可能被覆盖或没加载
为什么 host 写对了还是连不上
localhost 和 127.0.0.1 在 MySQL 里是两个完全不同的 host,权限记录互不通用:
-
'root'@'localhost'允许走 Unix socket 连接,但不自动允许127.0.0.1的 TCP 连接 - ThinkPHP 默认用 TCP,你配
host => 'localhost',PDO 却可能 fallback 到 socket;而 MySQL 8+ 默认禁用 socket(尤其 Mac M1 Homebrew 安装),结果就是“连得上却报 1045” - Docker 环境中,
host写127.0.0.1或localhost指向容器自身,不是宿主机 MySQL,必须改成容器名(如mysql)或host.docker.internal
怎么验证 PHP 实际用的是哪组凭证
别信配置文件,要确认运行时真正加载的值:
立即学习“PHP免费学习笔记(深入)”;
- 在控制器里加一行:
dump(env('DB_HOST')); dump(env('DB_USERNAME')); dump(env('DB_PASSWORD'));,输出null就说明.env根本没生效 -
.env生效有三个硬前提:文件必须在项目根目录(和think命令同级)、APP_DEBUG=true、键名全大写加下划线(DB_PASSWORD✅,db_password❌) - CLI 和 Web 运行环境可能不同:Apache 的
SetEnv、Nginx 的fastcgi_param、shell 的export三者不互通,用php -r "print_r($_ENV);"在命令行测,再用print_r($_SERVER)在 Web 页面测,对比差异
MySQL 8+ 的 caching_sha2_password 插件问题
错误信息里如果含 caching_sha2_password,不是密码错了,是 PHP 扩展(尤其是旧版 mysqlnd)压根不支持这个认证方式:
- 先查用户当前插件:
SELECT user, host, plugin FROM mysql.user WHERE user = 'root'; - 强制切回兼容模式:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_real_password'; FLUSH PRIVILEGES; - 如果用户 host 是
%或具体 IP,记得把'localhost'替成对应值,否则改了也没用
真正卡住人的地方,往往不是“不会配”,而是以为配对了——比如 .env 文件放错位置导致凭证为空,或 localhost 和 127.0.0.1 权限没同步,又或者 MySQL 8 的认证插件在后台悄悄拦下了连接。每一步都得用命令行交叉验证,不能只信框架日志。



















