PDO: MySQL server has gone away

I had the same problem where the hosting server administration kills connection if there is a timeout.

Since I have used the query in major part I wrote a code which instead of using PDO class we can include the below class and replace the classname to "ConnectionManagerPDO". I just wrapped the PDO class.

final class ConnectionManagerPDO
{

    private $dsn;
    private $username;
    private $passwd;
    private $options;
    private $db;
    private $shouldReconnect;

    const RETRY_ATTEMPTS = 3;

    public function __construct($dsn, $username, $passwd, $options = array())
    {
        $this->dsn = $dsn;
        $this->username = $username;
        $this->passwd = $passwd;
        $this->options = $options;
        $this->shouldReconnect = true;
        try {
            $this->connect();
        } catch (PDOException $e) {
            throw $e;
        }
    }

    /**
     * @param $method
     * @param $args
     * @return mixed
     * @throws Exception
     * @throws PDOException
     */
    public function __call($method, $args)
    {
        $has_gone_away = false;
        $retry_attempt = 0;
        try_again:
        try {

            if (is_callable(array($this->db, $method))) {

                return call_user_func_array(array($this->db, $method), $args);
            } else {

                trigger_error("Call to undefined method '{$method}'");
                /*
                 * or
                 *
                 * throw new Exception("Call to undefined method.");
                 *
                 */
            }
        } catch (\PDOException $e) {

            $exception_message = $e->getMessage();

            if (
                ($this->shouldReconnect)
                && strpos($exception_message, 'server has gone away') !== false
                && $retry_attempt <= self::RETRY_ATTEMPTS
            ) {
                $has_gone_away = true;
            } else {
                /*
                 * What are you going to do with it... Throw it back.. FIRE IN THE HOLE
                 */
                throw $e;
            }
        }

        if ($has_gone_away) {
            $retry_attempt++;
            $this->reconnect();
            goto try_again;
        }
    }


    /**
     * Connects to DB
     */
    private function connect()
    {
        $this->db = new PDO($this->dsn, $this->username, $this->passwd, $this->options);
        /*
         * I am manually setting to catch error as exception so that the connection lost can be handled.
         */
        $this->db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
    }

    /**
     * Reconnects to DB
     */
    private function reconnect()
    {
        $this->db = null;
        $this->connect();
    }
}

Then use can start using the above class as you do in PDO.

try {
    $db = new ConnectionManagerPDO("mysql:host=localhost;dbname=dummy_test", "root", "");
    $query = $db->query("select * from test");
    $query->setFetchMode(PDO::FETCH_ASSOC);
}
catch(PDOException $e){
    /*
        handle the exception throw in ConnectionManagerPDO
    */
}

The B.5.2.9. MySQL server has gone away section of the MySQL manual has a list of possible causes for this error.

Maybe you are in one of those situations ? -- Especially considering you are running a long operation, the point about wait_timeout might be interesting...


Most likely you sent a packet to the server that is longer than the maximum allowed packet.

When you try to insert a BLOB that exceeds your server's maximum packet size, even on a local server you will see the following error message on clientside:

MySQL server has gone away

And the following error message in the server log: (if error logging is enabled)

Error 1153 Got a packet bigger than 'max_allowed_packet' bytes

To fix this, you need to decide what is the size of the largest BLOB that you will ever insert, and set max_allowed_packet in my.ini accordingly, for example:

[mysqld]
...
max_allowed_packet = 200M
...

Tags:

Mysql

Php

Pdo