|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2014-08-26 22:55 UTC] ablyler at barracuda dot com
Description:
------------
The MYSQLI_OPT_CONNECT_TIMEOUT is ignored when using mysqlnd. To reproduce this run:
netstat -l -p 9999
Then execute the included test script (wrapped with time).
Thanks to Jason Dictos for coming up with the fix to this.
Test script:
---------------
<?php
$connect_timeout = 5;
$resource = mysqli_init();
if (!mysqli_options($resource, MYSQLI_OPT_CONNECT_TIMEOUT, $connect_timeout))
{
die('Unable to set connect timeout on resource');
}
var_dump(mysqli_real_connect($resource, '127.0.0.1', 'username', 'password', 'database', 9999));
Expected result:
----------------
It should return in ~5 seconds with errors.
Actual result:
--------------
The script will keep running past the timeout value.
Patchesmysqlnd-connection-timeout.patch (last revision 2014-08-26 22:56 UTC by ablyler at barracuda dot com)Pull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Fri Oct 24 19:00:01 2025 UTC |
This bug still persists in PHP 7.2.4. This is more than just a bug, it in effect DoSed a production system I manage. I run a series of MariaDB nodes in a Galera cluster. One of the nodes misbehaved. This happens from time to time. When a connection issue happens normally with a Galera node, it is pulled out of the local list of available nodes stored on each PHP instance. This process of storing and updating the list of Galera nodes is handled within a PHP script based on successful/failure to connect to each node. The problem is that even with MYSQLI_OPT_CONNECT_TIMEOUT set, no timeout happens if a successful TCP handshake is made but no data is transmitted over the wire afterwards. PHP is left in a hung state that can only be broken by restarting the entire PHP-FPM service. This leads to an eventual resource exhaustion within PHP-FPM hitting its maximum open connection limit as more users access the web site. This eventually breaks the entire web site. Simple code to reproduce: $sql = mysqli_init(); $sql->options(MYSQLI_OPT_CONNECT_TIMEOUT, 1); $sql->real_connect('google.com:80', 'user', 'my_password', 'db'); echo 'GOOD'; NOTE that using a web server such as google.com, the server side will eventually break the connection. HOWEVER, the short timeout of 1 second never happens, and instead the server side breaks the connection after the server side timeout value. In the case of MariaDB with the single node that misbehaved, it never broke the connection. Instead, no data was ever transmitted over the wire after the TCP handshake, leaving PHP in an endless waiting process. Nothing after $sql->real_connect() is ever processed, therefor any sysadmin related emails about a failed connection or automatically pulling the failed node from the server pool ever happened as a result.