2006

MySQL 2006: MySQL server has gone away fix

Database Errors Intermediate 👁 1 views 📅 May 25, 2026

MySQL throws 2006 when the server closes the connection mid-query. Usually from timeout, oversized packets, or server restart.

Quick answer

Increase max_allowed_packet to 64M or more, and raise wait_timeout and interactive_timeout to 28800 in my.cnf, then restart MySQL. If it still breaks, your server is crashing under load or someone's killing the connection.

What's actually happening here

MySQL error 2006 means the server closed the connection before your query finished. The server doesn't send a goodbye—it just drops you. Three things cause this:

  • Packet too large – MySQL has a default limit of 4MB or 16MB (depends on version) for any single packet. Blob columns, large JSON inserts, or stored procedures returning big resultsets will blow past this. MySQL kills the connection without warning.
  • Timeout – The server's wait_timeout (default 28800 seconds for interactive, 60 seconds for non-interactive) kills idle connections. Long-running scripts that pause between queries hit this.
  • Server crash or restart – MySQL went down and back up. Your client still holds the old connection handle. Next query fails.

I've seen this most frequently when someone runs an INSERT ... SELECT that moves terabytes of data, or a cron job that runs a heavy UPDATE every 5 minutes and the server's innodb_buffer_pool runs dry. The error message is sparse, but the fix path is clear.

Fix steps – in order of likelihood

  1. Check MySQL error logtail -100 /var/log/mysql/error.log (or /var/log/mysqld.log on RHEL). Look for Aborted connection, Too many connections, or Out of memory. If you see a memory error, skip packet size—your server needs more RAM or query optimization.
  2. Bump max_allowed_packet – Open /etc/mysql/my.cnf or /etc/my.cnf and set:
    [mysqld]
    max_allowed_packet=64M
    Restart: systemctl restart mysql. Test with SHOW VARIABLES LIKE 'max_allowed_packet'; If you're on MariaDB, same variable name. For AWS RDS, set via parameter group.
  3. Raise timeouts – Add these under [mysqld]:
    wait_timeout=28800
    interactive_timeout=28800
    28800 seconds = 8 hours. Adjust to your needs. If you have persistent connections (PHP's PDO with ATTR_PERSISTENT), non-interactive clients use wait_timeout, interactive ones use interactive_timeout.
  4. Check for server restarts – Run uptime on the MySQL host. If the server came up recently, check grep -i 'restart' /var/log/mysql/error.log. If MySQL keeps crashing, you're probably hitting Out of memory from large joins or insufficient swap. Add innodb_buffer_pool_size = 70% of RAM (e.g., 14GB on 20GB machine) and tmp_table_size = 64M.
  5. Verify network stability – If MySQL is remote, check netstat -s | grep reset. TCP resets from firewalls or load balancers can drop connections mid-query. Add tcp_keepalive_time = 600 to /etc/sysctl.conf.

Alternative fixes – when the main ones fail

  • PHP specifically – In PDO, set PDO::ATTR_EMULATE_PREPARES = false and catch 2006 errors with a reconnect loop:
    try {
        $pdo->query('SELECT 1');
    } catch (PDOException $e) {
        if ($e->getCode() == 2006) {
            $pdo = new PDO($dsn, $user, $pass);
        }
    }
    This isn't ideal – you're masking a systemic problem. Fix the root cause first.
  • Python / SQLAlchemy – Use pool_pre_ping=True in create_engine(). It tests connections before handing them out. If the test fails, it opens a new one. Reduces but doesn't eliminate the error.
  • For large inserts (blobs, JSON) – Split your data into chunks of 1MB each and insert in a loop. MySQL can handle multiple small packets better than one huge one. Example with 1000 rows per INSERT.

Prevention tip – what I do in production

Set max_allowed_packet to 64MB before you ever need it. It costs you nothing. For timeouts, use wait_timeout=3600 (1 hour) on web apps—long enough for most queries, short enough to free connections from dead scripts. Use connection pooling (ProxySQL, PgBouncer for MySQL) to reuse connections and avoid handshake costs. Monitor Aborted_connects and Aborted_clients in SHOW GLOBAL STATUS – they're early warning signs. And for the love of databases, never run a production MySQL on a machine with less than 2GB of RAM if you're doing anything beyond a toy app.

Was this solution helpful?