MySQL连接超时由MySQL服务端(connect_timeout)、网络链路(系统级socket超时)和PHP客户端库共同控制,Laravel仅能通过PDO::ATTR_TIMEOUT影响查询执行超时,无法干预连接建立阶段。

MySQL 连接超时由谁控制?不是 Laravel 说了算
连接超时根本不在 Laravel 配置里硬编码,它分三层:PHP PDO 层、MySQL 服务端、网络链路。Laravel 的 config/database.php 中的 options 只能传给 PDO 构造函数,而 PDO 本身不处理连接超时——它把底层连接交给 MySQL 客户端库(如 mysqlnd)去管。
常见错误现象:PDOException: SQLSTATE[HY000] [2002] Connection timed out 或卡在 DB::connection()->getPdo() 不返回。这不是 Laravel 慢,是 TCP 握手或 MySQL server 拒绝响应导致的。
- MySQL 服务端控制项:
connect_timeout(单位秒,默认 10),影响服务端接受连接的等待上限 - PDO 无法设置 TCP 层超时,但可通过
PDO::ATTR_TIMEOUT影响**语句执行**超时(非连接) - 真正能干预连接阶段的,只有 PHP 的
mysqli或自定义 socket stream context,Laravel 默认不走这条路
Laravel 中能改的只有「连接后」行为:PDO::ATTR_TIMEOUT 和重连逻辑
PDO::ATTR_TIMEOUT 是唯一 Laravel 配置能触达的“超时”参数,但它只作用于 查询执行阶段,不是连接建立。设成 5 表示某条 DB::table('users')->where(...)->get() 卡住超过 5 秒就抛异常,和连不上数据库完全无关。
实操建议:
- 在
config/database.php的 MySQL 配置块中加:'options' => [ PDO::ATTR_TIMEOUT => 5, ] - 这个值对长事务、大结果集导出很关键;但设太小会导致正常慢查被误杀
- 搭配
'retries' => 2(Laravel 9+ 支持)可缓解瞬时连接抖动,但它只在 query 失败后重试,不解决首次 connect 失败
真要调连接超时,得动 MySQL 服务端或 PHP 环境
如果经常遇到 Connection refused 或 Operation timed out,优先检查 MySQL 服务是否健康、防火墙是否放行、DNS 是否解析慢。连接超时本质是操作系统级 socket connect() 调用的 timeout,Linux 默认约 21 秒,不可通过 PHP/Laravel 修改。
可行路径:
- MySQL 侧:登录后执行
SHOW VARIABLES LIKE 'connect_timeout';,修改my.cnf中的connect_timeout = 3并重启 mysqld(注意过低可能导致负载高时合法连接被拒) - PHP 侧:若用
pdo_mysql,无法干预 connect timeout;若切到mysqli,可用mysqli_options($conn, MYSQLI_OPT_CONNECT_TIMEOUT, 3),但 Laravel 不原生支持 - 云环境(如 RDS):有些厂商提供“连接池超时”或“代理层 idle timeout”,需查对应控制台文档,不是改代码能解决的
本地开发 vs 生产环境的 timeout 表现差异极大
本地用 127.0.0.1 连 MySQL,connect 几乎不超时;上生产走内网或跨 AZ,中间有 SLB、安全组、NAT 网关,任意一环卡住都会触发系统级 timeout。这时候看日志里的错误前缀特别重要:SQLSTATE[HY000] [2002] 是连接失败,SQLSTATE[HY000] [2013] 才是查询过程中断连。
容易被忽略的点:
- Docker 环境下宿主机 hosts 绑定错误、或使用
host.docker.internal但未开启对应选项,会导致 DNS 解析卡住几十秒才 fallback - Laravel Octane + Swoole 下,连接复用会让 timeout 行为更隐蔽——一个 worker 进程里 PDO 实例复用,上次连接已断但没检测,下次 query 直接 hang
- 不要在
.env里写DB_HOST=localhost,它会强制走 Unix socket(如果 mysqld 配了 socket),而实际想走 TCP;应明确写127.0.0.1


















