MySQLi连接超时必须在mysqli_init()后、mysqli_real_connect()前用mysqli_options()设置,否则无效;mysqli_connect()不支持运行时设超时,PDO::ATTR_TIMEOUT控制查询而非连接超时,真正连接超时由系统TCP或DNS决定。

MySQLi 连接超时设置不生效?检查 mysqli_options() 调用时机
连接超时(MYSQLI_OPT_CONNECT_TIMEOUT)必须在 mysqli_init() 之后、mysqli_real_connect() 之前设置,否则被忽略。常见错误是先调用 new mysqli() 或直接 mysqli_connect(),再试图用 mysqli_options() 补救——这时连接已发起,选项无效。
正确做法:
$mysqli = mysqli_init(); mysqli_options($mysqli, MYSQLI_OPT_CONNECT_TIMEOUT, 3); // 3秒超时 mysqli_real_connect($mysqli, 'localhost', 'user', 'pass', 'db', 3306);
-
mysqli_connect()是封装函数,不支持运行时设连接超时,只能靠mysqli_init() + mysqli_real_connect()组合 - 若用 PDO,对应的是
PDO::ATTR_TIMEOUT,但注意它控制的是**查询执行超时**,不是连接超时 - PHP-FPM 环境下,还要确认
max_execution_time没有早于连接超时就中断脚本
pdo\_mysql 连接超时靠 DNS 和 socket 层,PDO::ATTR_TIMEOUT 不管用
PDO::ATTR_TIMEOUT 实际控制的是语句执行(execute())的等待时间,对 TCP 建连无影响。真正影响“连不上”的,是底层 socket 连接行为:
- Linux 下默认 TCP connect 超时约 20–30 秒,无法通过 PDO 参数缩短
- 若 MySQL 服务端地址是域名,DNS 解析失败也会卡满这个时间;建议在
host中直接写 IP,或确保本地/etc/hosts有映射 - 使用
unix_socket(如/var/run/mysqld/mysqld.sock)可绕过网络层,大幅降低连接延迟和不确定性
示例(强制走 socket):
立即学习“PHP免费学习笔记(深入)”;
$pdo = new PDO('mysql:unix_socket=/var/run/mysqld/mysqld.sock;dbname=test', $user, $pass);
PHP 进程卡在 mysql_connect()?那是被系统级 connect 阻塞了
旧式 mysql_connect()(已废弃)或未设超时的 mysqli_connect(),一旦目标 IP 不可达或防火墙拦截,PHP 进程会阻塞在系统 connect() 系统调用上,直到内核返回 ETIMEDOUT —— 这个时间由内核决定,PHP 无法干预。
- 不要依赖
set_time_limit()来打断这种阻塞,它只对 PHP 用户态代码计时,对系统调用无效 - 唯一可靠方式是改用非阻塞 socket +
stream_select()自行实现连接逻辑,或换用mysqli_init() + mysqli_real_connect()配合MYSQLI_OPT_CONNECT_TIMEOUT - 线上环境务必禁用
mysql_*()函数,它们不支持任何超时控制,且 PHP 7+ 已移除
数据库连接池或长连接没释放?mysqli_close() 不是万能的
即使设置了连接超时,如果前一次连接因异常未关闭,而脚本又复用连接资源(比如用了 PDO::ATTR_PERSISTENT),可能导致后续连接被卡在“等待可用连接”状态,看起来像超时。
- 持久连接(
persistent)的超时由 MySQL 服务端wait_timeout控制,PHP 层无法覆盖 - 手动调用
mysqli_close()对持久连接无效;要真正断开,得用mysqli_kill()或确保脚本结束时连接自动回收 - 高并发下建议关闭持久连接,改用连接池中间件(如 ProxySQL)或短连接 + 连接复用优化
真正难调试的,往往是超时设置写了,但被更高优先级的系统行为覆盖,或者你以为在控制连接,其实卡在 DNS 或 socket 队列里。











