21

I'm testing scenarios where the mysql server cannot be reached by putting in a random IP to try to connect to. I set PDO's options to time out after one second using PDO::ATTR_TIMEOUT => 1. However, it still takes 30 seconds to throw an exception. I'm guessing this timeout only applies to the actual mysql connection time, not to the server on which mysql is running.

What PHP options do I need to change to time out the connection to the mysql server?

timetofly
  • 2,957
  • 6
  • 36
  • 76
  • A few questions - how do you set `PDO::ATTR_TIMEOUT`, i.e. what is your connection string? Do you use MySQLnd or the regular mysql driver? What version is your PHP and also the mysql driver? – VolenD May 14 '15 at 20:39
  • You should post the complete code that you're using to connect to the mysql DB. – Pedro Lobito May 18 '15 at 17:30
  • 4
    There's no point in starting a bounty and not to add the additional info commenter are requesting. – MatteoSp May 20 '15 at 23:19
  • @MatteoSp I apologize, after I started the bounty I became super busy. As for the connection string, it's pretty much what nobody0day posted. It's the default Laravel connector + the timeout, so it uses exception as the error mode. – timetofly May 21 '15 at 14:58

6 Answers6

11

Just put

ini_set("default_socket_timeout", 2);

before your PDO() connect string.

(Tested on Windows, should also be fine on Linux.)


Why?

Chasing this through the manual:

The mysqlnd driver uses sockets for the underlying connection, and that to set timeouts you need to use the socket (stream) timeout functions. (Ref: http://php.net/manual/en/mysqlnd.notes.php)

Using mysqlnd means using PHP streams for underlying connectivity. For mysqlnd, the PHP streams documentation (Streams) should be consulted on such details as timeout settings, not the documentation for the MySQL Client Library.


If you want more control, then you might be able to control more specifically the actual socket: I've not tested this as it's unix only. To set the socket mysqlnd uses, you can specify the socket using ini settings (Ref: http://php.net/manual/en/ref.pdo-mysql.connection.php)

If PDO_MYSQL is compiled against mysqlnd a default socket can be set thru the pdo_mysql.default_socket setting.

See http://php.net/manual/en/ref.pdo-mysql.php#ini.pdo-mysql.default-socket about that setting

You might be able to then set the timeout using http://php.net/manual/en/function.stream-set-timeout.php

But probably easier to set default and then reset once you're done...

Robbie
  • 17,605
  • 4
  • 35
  • 72
  • Interesting. If I set `default_socket_timeout` to 1 second but don't use the PDO connection timeout option, shouldn't it still timeout after a second? I only ask because I'm not sure what happened, but the pdo timeout started working for me out of the blue, though the same issue still happens with memcached connections. – timetofly May 21 '15 at 16:05
  • That is correct. Memcache had a timeout as a parameter in the connect function. So use the default socket timeout for mysqlnd, and parameters for memcached – Robbie May 21 '15 at 22:10
5

On the php.ini you can update this config variable:

mysql.connect_timeout = 1
Akram Fares
  • 1,653
  • 2
  • 17
  • 32
2

Pass the options to the PDO constructor:

https://github.com/phalcon/cphalcon/blob/2.0.0/phalcon/db/adapter/pdo.zep#L135-L149

Alpesh Rathod
  • 385
  • 3
  • 10
  • 1
    Please include the actual solution in your answer. The link doesn't work anymore, because the repo has changed in some way. – mbomb007 Dec 16 '19 at 22:18
2

For me, if you put the option in the constructor of PDO, it works. And ignores any settings in php.ini

$options = array(PDO::ATTR_TIMEOUT => 1); // must be in the constructor
$db = new DB($dsn, $username, $password, $options);

Since here we are testing the initial connection, it makes sense that it needs to have this option, when opening the connection. So below should work for any queries AFTER the initial connection.

$db = new DB($dsn, $username, $password, $options);
$db->setAttribute(PDO::ATTR_TIMEOUT, 1);
Robert
  • 664
  • 9
  • 25
Aris
  • 4,643
  • 1
  • 41
  • 38
1

PDO::ATTR_TIMEOUT: Specifies the timeout duration in seconds. Not all drivers support this option, and its meaning may differ from driver to driver. For example, sqlite will wait for up to this time value before giving up on obtaining an writable lock, but other drivers may interpret this as a connect or a read timeout interval.

The document clearly stated that it might not mean a connection timeout interval or sometimes driver does not support it.

invisal
  • 11,075
  • 4
  • 33
  • 54
  • 1
    This is certainly not the case with MySQL driver on Linux - for example if you set `PDO::ATTR_TIMEOUT` to 7 and `strace` a script making connection, you will see `connect(3, {sa_family=AF_INET, sin_port=htons(3306), sin_addr=inet_addr("10.0.0.0")}, 16) = -1 EINPROGRESS (Operation now in progress) poll([{fd=3, events=POLLIN|POLLPRI}], 1, 7000` – VolenD May 19 '15 at 09:26
  • I'm using mysqlnd, which supposedly supports it. – timetofly May 19 '15 at 12:43
1

    $host = '192.168.1.36';
    $dbname = 'test';
    $username = 'test';
    $password = '';

    $start = time();
    try {
        $db = new PDO(
            "mysql:host=$host;dbname=$dbname", 
            $username, 
            $password,
            array(
                PDO::ATTR_TIMEOUT => 1,
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
            )
        );
    } catch(Exception $e) {
        echo time() - $start;
        echo "\n";
        echo $e->getMessage();
    }

This code snippet should solve your problem.

difference of mysqli, mysqlnd, pdo-mysql:

  • (deprecated) mysqlnd means msyql native driver which functions are procedural
  • mysqli object form of mysql diriver
  • pdo-mysql is plugin for pdo database abstraction to support connecting to mysql database.
nobody0day
  • 180
  • 2
  • 7
  • 4
    Your comments about the native driver are VERY wrong. It is very un-deprecated. This library offers far more control than the original mySQL drivers and should be used (e.g. integers are returned as integers, not strings, native prepared statements are available). http://php.net/manual/en/intro.mysqlnd.php The old mysql() functions are deprecated: this is not connected to the native driver at all. – Robbie May 21 '15 at 03:20