PDO::MYSQL_ATTR_CONNECT_TIMEOUT才真正控制连接超时,PDO::ATTR_TIMEOUT对MySQL无效;localhost常因默认走socket而失败,应改用127.0.0.1并显式传参设置超时。

PDO::MYSQL_ATTR_CONNECT_TIMEOUT 才真管建连超时,PDO::ATTR_TIMEOUT 完全无效——它只对 SQLite 生效,加了反而让你误以为已生效。
为什么 localhost 总连不上?先换 127.0.0.1
Windows(尤其是 phpEnv)下 localhost 默认走命名管道或 Unix socket,但 MySQL 实际监听的是 127.0.0.1:3306;Docker 或云环境里若没配 bind-address = 0.0.0.0,外部 PHP 就连不上。直接把 DSN 里的 host=localhost 换成 host=127.0.0.1,多数“超时”当场消失。
PDO::MYSQL_ATTR_CONNECT_TIMEOUT 必须显式传参,DSN 里写无效
connect_timeout=3 写在 DSN 里基本不起作用,尤其在 phpEnv 或旧版 mysqlnd 下。必须用选项数组传参:
$pdo = new PDO(
'mysql:host=127.0.0.1;dbname=test',
'user',
'pass',
[
PDO::MYSQL_ATTR_CONNECT_TIMEOUT => 3, // 单位秒,建议 3–5
PDO::MYSQL_ATTR_READ_TIMEOUT => 10,
PDO::MYSQL_ATTR_WRITE_TIMEOUT => 10,
]
);
-
PDO::ATTR_TIMEOUT对 MySQL 完全没用,删掉别留着 - 读写超时要分开设,
PDO::MYSQL_ATTR_READ_TIMEOUT和PDO::MYSQL_ATTR_WRITE_TIMEOUT才真正起效 - 超时值别设太小:公网环境建议 ≥5 秒,内网可压到 3 秒
MySQLi 怎么设连接超时?不能用 mysqli_connect()
mysqli_connect() 是封装函数,不支持运行时设超时。必须拆开三步:
$mysqli = mysqli_init(); mysqli_options($mysqli, MYSQLI_OPT_CONNECT_TIMEOUT, 3); mysqli_real_connect($mysqli, '127.0.0.1', 'user', 'pass', 'test', 3306);
-
mysqli_options()必须在mysqli_real_connect()之前调用,否则被忽略 - 如果已经用了
new mysqli(),那超时设置早就失效了,得重写 - 读写超时同理:用
MYSQLI_OPT_READ_TIMEOUT和MYSQLI_OPT_WRITE_TIMEOUT
连接断了怎么办?别信 PDO::ping() 和 mysqli_ping()
这两个方法在 CLOSE_WAIT 状态下可能返回 true,但实际已断。TP6 等框架默认也不检测连接存活。最稳妥做法是每次 query 前轻量探测:
立即学习“PHP免费学习笔记(深入)”;
try {
$pdo->getAttribute(PDO::ATTR_SERVER_INFO);
} catch (\PDOException $e) {
if (strpos($e->getMessage(), 'MySQL server has gone away') !== false) {
$pdo = null; // 或触发重建逻辑
}
}
- 用
getAttribute(PDO::ATTR_SERVER_INFO)比SELECT 1更轻量,不发 SQL 包 - 长生命周期进程(如队列 worker)必须每 8 秒内探测一次,不能靠 wait_timeout 配置硬扛
-
PDO::ATTR_PERSISTENT => true不解决断连问题,MySQL 仍会按自己的规则清理空闲连接



















