SQLSTATE[HY000] [2002] Connection refused本质是TCP连接被拒绝,主因包括DB_PORT错配(如33060)、MySQL未启动、防火墙拦截、Docker网段冲突或host配置不当(127.0.0.1与localhost行为差异)。

DB_PORT 写错时页面直接卡死或报 Connection refused
不是抛出 SQL 语法错误,也不是 404 或 500 页面,而是 PHP 连接数据库超时后返回 SQLSTATE[HY000] [2002] Connection refused。这个错误本质是 TCP 层连接被拒绝,说明 PHP 尝试连一个根本没在监听的端口。
常见诱因包括:DB_PORT 值多写了一个 0(比如写成 33060)、漏掉引号导致被解析为空、或复制配置时把注释也粘进去了。
- MySQL 默认端口是
3306,PostgreSQL 是5432,别凭印象写成3307或8080 - 如果用 Docker,确认容器实际映射的端口,
docker ps查看PORTS列,别只看宿主机.env配置 -
DB_HOST=127.0.0.1和DB_HOST=localhost在端口行为上也可能不同(前者走 TCP,后者可能走 socket),端口错配时表现不一致
artisan 命令执行失败但错误信息不明确
运行 php artisan migrate 或 php artisan tinker 后卡住几秒,然后报类似 PDOException: SQLSTATE[HY000] [2002] No such file or directory —— 注意这个提示容易误导,它不一定真缺 socket 文件,也可能是端口不通导致底层连接机制 fallback 失败。
验证方式很简单:
- 终端执行
telnet 127.0.0.1 3306(或你配的DB_PORT),如果显示Connection refused,基本就是端口错了或 MySQL 没启 - 换用
nc -zv 127.0.0.1 3306更可靠,能明确告诉你端口是否 open - 不要依赖
php artisan tinker里敲DB::connection()->getPdo(),它可能缓存了旧连接状态
日志里看不到真实连接目标,debug 成本陡增
Laravel 默认不会在日志中记录它试图连接的完整地址和端口,storage/logs/laravel.log 里只有抽象错误,比如 SQLSTATE[HY000] [2002],没有 tried connecting to 127.0.0.1:33060 这样的线索。
想确认实际连接参数,得临时加一行调试:
dd([
'host' => config('database.connections.mysql.host'),
'port' => config('database.connections.mysql.port'),
'database' => config('database.connections.mysql.database'),
]);
放在某个路由闭包或命令的开头,比翻 .env 更可靠 —— 因为 env() 可能被缓存,或被运行时修改覆盖。
APP_ENV=production 下几乎无法定位问题
生产环境 APP_DEBUG=false 时,Connection refused 错误会被吞掉,前端只看到空白页或通用 500,laravel.log 里也只有模糊的 PDO 异常堆栈,没有上下文。
这时候必须靠外部工具交叉验证:
- 先确认数据库进程活着:
ps aux | grep mysql或systemctl is-active mysql - 再确认监听端口:
ss -tuln | grep :3306(Linux)或lsof -i :3306(Mac) - 最后检查 Laravel 是否读到了正确值:
php artisan tinker --execute="echo config('database.connections.mysql.port');"
端口配置看着对,但被 config:cache 锁死、或被 Apache 的 SetEnv 覆盖,都是真实发生过的坑。


















