40

I'm doing an operation that inserts hundreds of records into a MySQL database.

After inserting exactly 176 records I get this error:

[PDOException] SQLSTATE[HY000]: General error: 2006 MySQL server has gone away

Any ideas of how could I solve it?

The process is with PHP.

TylerH
  • 20,799
  • 66
  • 75
  • 101
  • Are you on a shared server? – mseifert Oct 21 '15 at 03:33
  • Yes. GoDaddy. Is it related? –  Oct 21 '15 at 03:34
  • Probably. I have the same problem regularly with WebHostingHub. I haven't yet had any luck figuring out the "why." If you post your code, it might be easier to tell [what might be going on.](http://stackoverflow.com/questions/7942154/mysql-error-2006-mysql-server-has-gone-away?rq=1) – mseifert Oct 21 '15 at 03:43
  • Take a look at the top link under "related" for your post (with 58 votes). [The post](http://stackoverflow.com/questions/7942154/mysql-error-2006-mysql-server-has-gone-away?rq=1) – mseifert Oct 21 '15 at 03:45
  • Just for curiosity could you run this: SHOW VARIABLES LIKE '%timeout%'; –  Oct 21 '15 at 03:49
  • If your PHP process takes a while in between insertions of data, the connection to MySQL can close, MySQL connections are closed after being inactive for a certain time, so you can try making sure the connection is open in PHP and reconnecting if not – A_funs Oct 21 '15 at 03:58
  • I'm doing a $this->connect(), then a mysql_query and then a $this->disconnect() after every call. –  Oct 21 '15 at 04:02
  • This might sound weird but I'm trying doing a sleep(2); after every call. –  Oct 21 '15 at 04:05
  • wait_timeout=30 or 60 seconds is common gonzo time on shared servers. For many of us it is 28800 (I think) for 24 hours. or like 600. But for the likes of GoDaddy, the model is pay us, don't use us :) – Drew Oct 21 '15 at 04:09
  • Unfortunately it kept failing at exactly 176 records. The pause did nothing. Seems like will have to test this in a VPS, AWS or RedShift. –  Oct 21 '15 at 04:15
  • is it that a single call to a php is taking more than 60 seconds for the entire script to finish, or a single mysql command (like a slow join) to complete, or something else ? – Drew Oct 21 '15 at 04:17
  • as for AWS, you won't have any of your problems there. They have the [AWS Free Tier](https://aws.amazon.com/free/) if a micro instance is up your alley. Get an elastic IP over there, point your GoDaddy DNS records to that IP addr – Drew Oct 21 '15 at 04:18

6 Answers6

20

I would venture to say the problem is with wait_timeout. It is set to 30 seconds on my shared host and on my localhost is set for 28800.

I found that I can change it for the session, so you can issue the query: SET session wait_timeout=28800

UPDATE The OP determined that he also needed to change the variable interactive_timeout as well. This may or may not be needed for everyone.

The code below shows the setting before and after the change to verify that it has been changed.

So, set wait_timeout=28800 (and interactive_timeout = 28800) at the beginning of your query and see if it completes.

Remember to insert your own db credentials in place of DB_SERVER, DB_USER, DB_PASS, DB_NAME

UPDATE Also, if this does work, you want to be clear on what you are doing by setting wait_timeout higher. Setting it to 28800 is 8 hours and is a lot.

The following is from this site. It recommends setting wait_timeout to 300 - which I will try and report back with my results (after a few weeks).

wait_timeout variable represents the amount of time that MySQL will wait before killing an idle connection. The default wait_timeout variable is 28800 seconds, which is 8 hours. That's a lot.

I've read in different forums/blogs that putting wait_timeout too low (e.g. 30, 60, 90) can result in MySQL has gone away error messages. So you'll have to decide for your configuration.

<?php

$db = new db();

$results = $db->query("SHOW VARIABLES LIKE '%timeout%'", TRUE);
echo "<pre>";
var_dump($results);
echo "</pre>";

$results = $db->query("SET session wait_timeout=28800", FALSE);
// UPDATE - this is also needed
$results = $db->query("SET session interactive_timeout=28800", FALSE);

$results = $db->query("SHOW VARIABLES LIKE '%timeout%'", TRUE);
echo "<pre>";
var_dump($results);
echo "</pre>";


class db {

    public $mysqli;

    public function __construct() {
        $this->mysqli = new mysqli(DB_SERVER, DB_USER, DB_PASS, DB_NAME);
        if (mysqli_connect_errno()) {
            exit();
        }
    }

    public function __destruct() {
        $this->disconnect();
        unset($this->mysqli);
    }

    public function disconnect() {
        $this->mysqli->close();
    }

    function query($q, $resultset) {

        /* create a prepared statement */
        if (!($stmt = $this->mysqli->prepare($q))) {
            echo("Sql Error: " . $q . ' Sql error #: ' . $this->mysqli->errno . ' - ' . $this->mysqli->error);
            return false;
        }

        /* execute query */
        $stmt->execute();

        if ($stmt->errno) {
            echo("Sql Error: " . $q . ' Sql error #: ' . $stmt->errno . ' - ' . $stmt->error);
            return false;
        }
        if ($resultset) {
            $result = $stmt->get_result();
            for ($set = array(); $row = $result->fetch_assoc();) {
            $set[] = $row;
            }
            $stmt->close();
            return $set;
        }
    }
}
mseifert
  • 5,390
  • 9
  • 38
  • 100
  • It does on WebHostingHub and they seem to be equivalent. I must say I was surprised it worked. – mseifert Oct 21 '15 at 04:21
  • It did not work for me. Will have to try something else. Thanks anyway. –  Oct 21 '15 at 05:45
  • Did it not change the wait_timeout or did it change the wait_timeout but the 2006 error still happened? – mseifert Oct 21 '15 at 05:57
  • I was able to set the wait_timeout in the current transaction to 28800 but the process still failed. I'm wondering if this is related to another value. –  Oct 21 '15 at 17:43
  • Added a comment @mseifert. I accepted your post as the valid answer since you gave me the idea and part of the solution to solve this. Thanks! –  Oct 21 '15 at 17:54
  • Wooww si funciona, lo aplique a cada consulta de update o de insert ya que solo se me estaba presentando en estas ocaciones – FuriosoJack Sep 22 '21 at 14:32
7

Thanks @mseifert.

Your idea worked by doing the same with two variables.

interactive_timeout & wait_timeout

I copied the config from a local database:

SHOW VARIABLES LIKE  '%timeout%'

Local db:

enter image description here

Remote db:

enter image description here

I did this inside the connect and disconnect and worked:

mysql_query("SET SESSION interactive_timeout = 28800;");
$result = mysql_query("SHOW VARIABLES LIKE 'interactive_timeout';");
$row = mysql_fetch_array($result);
$interactive_timeout = $row["Value"];
echo("interactive_timeout" . " = " . $interactive_timeout . "\n");

mysql_query("SET SESSION wait_timeout = 28800;");
$result = mysql_query("SHOW VARIABLES LIKE 'wait_timeout';");
$row = mysql_fetch_array($result);
$wait_timeout = $row["Value"];
echo("wait_timeout" . " = " . $wait_timeout . "\n");

Surprisingly it worked with GoDaddy.

I will accept your answer as valid @mseifert since you gave me the original idea.

Thanks a lot.

Let us hope this is useful in the future to solve the 2006 MySQL error for other developers.

  • That is very interesting. I read that interactive_timeout was for mysql shell sessions like mysqldump or mysql command line tools. In any event, good work on solving the problem. I will update my answer to include this info since you've made it the accepted answer. – mseifert Oct 22 '15 at 03:17
  • By the way, I have to add something else. The massive sql insertion that I did could be called via web browser through a REST API but also via console - command line. Maybe that's why I had to add both options. –  Oct 22 '15 at 19:05
4

In my case, when I got this error on the client side, the server side was

(Got a packet bigger than 'max_allowed_packet' bytes)

So I increase the value of the max_allowed_packet, and so far, no more issues.

On Google Cloud Platform, I edit the DB and add a Database flag and set the value to max_allowed_packet=134217728

(which is 2^27 = 128M)

As you can only input numbers.

On regular instances, you can follow the doc here :

https://dev.mysql.com/doc/refman/8.0/en/packet-too-large.html

Thomas
  • 1,231
  • 14
  • 25
0

Assume your codes is:

// your codes
$pdo = db::connection()->getPdo();
$stmt = $pdo->prepare($sql);
$result = $stmt->execute($params);

So add below codes before your sql query:

$pdo = db::connection()->getPdo();

// Increase interactive_timeout
$prepend_sql = "SET SESSION interactive_timeout = 28800;";
$stmt = $pdo->prepare($prepend_sql);
$stmt->execute($params);

// Increase wait_timeout 
$prepend_sql = "SET SESSION wait_timeout = 28800;";
$stmt = $pdo->prepare($prepend_sql);
$stmt->execute($params);

// your codes
/* $pdo = db::connection()->getPdo(); */
$stmt = $pdo->prepare($sql);
$result = $stmt->execute($params);
Amin
  • 1,089
  • 8
  • 7
-1

Another possible reason would be your client is trying to connect using SSL. while the MySQL/MariaDB server is not expecting that.

Shiji.J
  • 1,561
  • 2
  • 17
  • 31
  • Please add some explanation to your answer such that others can learn from it. How could the problem be resolved? Also, if 176 rows could be inserted properly, how should such an SSL error be triggered afterwards? – Nico Haase Nov 07 '22 at 10:29
-2

a solution is to check if the connection is active, if not re-establishing the connection, here it worked perfectly

<?php

require_once ('config.php');

class DB {

    private static $instance;
    
    private function __construct() {
        ;
    }
    
    public static function getInstance() {
        if (!isset(self::$instance)) {
            try {
                self::$instance = new PDO('mysql:host=' . DB_HOST . ';dbname=' . DB_NAME, DB_USER, DB_PASS);
                self::$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                self::$instance->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
            } catch (PDOException $e) {
                echo $e->getMessage();
            }
        }
        
        try {
            $testConn = self::$instance->prepare('SELECT 1');
            $testConn->execute();
            $testConn = $testConn->fetchAll(PDO::FETCH_ASSOC)[0];
        } catch (Exception $ex) {
            try {
                self::$instance = new PDO('mysql:host=' . DB_HOST . ';dbname=' . DB_NAME, DB_USER, DB_PASS);
                self::$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                self::$instance->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
            } catch (PDOException $e) {
                echo $e->getMessage();
            }
        }

        return self::$instance;
    }

    public static function prepare($sql) {
        return self::getInstance()->prepare($sql);
    }
    
    public static function lastInsertId() {
        return self::getInstance()->lastInsertId();
    }

}

Mustafa Poya
  • 2,615
  • 5
  • 22
  • 36
Rafael Abne
  • 11
  • 1
  • 2