Troubleshooting guide · website-errors · Published 2026-08-16 · 4 min read
MySQL "server has gone away" error
MySQL server has gone away: raise wait_timeout and max_allowed_packet, close idle connections, and find the restart that ends the error.
- ·The four causes
- ·Read the MySQL log
- ·Apply the fixes in order
Symptoms
The page fails with MySQL server has gone away ("MySQL server has gone away" in PHP/WordPress, mysqli::query(): MySQL server has gone away, or a 500 with a log line beneath). The signature is timing: it happens on a long query, on an import, on a nightly task, or after a few hours of quiet, and a hard refresh often works because the connection was simply rebuilt.
The four causes
The MySQL client reopens a connection only when it breaks. "Server has gone away" means one of four things happened to the connection it was using:
- The server killed the idle connection.
wait_timeout(default 28800s) closes a connection that has been open past the limit, and older pooled connections return to the pool and die on the next query. The "goes away" right after a quiet night is this one. - The query or the reply was bigger than
max_allowed_packet. A 2 MB field, a largeINSERT ... VALUES, or a bigSELECTkills the connection when the packet limit is crossed (default 4 MB to 64 MB depending on version). - The database server restarted underneath it.
mysqldrebooted during the request: the host rebooted, Out Of Memory killer killed it, or a crash loop. The log shows[ERROR] Aborting. - A long transaction or
max_execution_timecut the query then the client fell over while PHP timed out with the connection still open.
Read the MySQL log first
The error log distinguishes the four causes in one look:
[Note] Aborted connection <id> to db: 'app' user: 'app' <charset>
Warning: TIMEOUT on connection
[ERROR] Aborted connection ... Got timeout reading communication packets
[ERROR] [MY-011086] InnoDB ... crash recovery
- A
Note/Warningabout a timed-out connection that completes is the idle-timeout case. - An
[ERROR]namingInnoDBor a shutdown line means the server actually died (restart case). - A
Got packet bigger than 'max_allowed_packet'line is the packet case.
On shared hosting, the MySQL log is usually in the panel ("Database" or "Logs"); on a VPS it's /var/log/mysql/error.log.
The fixes in order
- Raise
wait_timeoutwhere the client side is the offender. Setwait_timeoutto the longest batch job length plus headroom (e.g. 180 to 300 seconds instead of 60 on the host). If the site uses persistent connections (db connections left open in fastcgi), they will still die at the limit; a pool that reconnects is better than a single long-lived socket. - Raise
max_allowed_packet. For uploads and bulk imports:SET GLOBAL max_allowed_packet=134217728(128 MB), and set it inmy.cnfunder[mysqld]so it survives restart. Then restart or reconnect. - Keep the connection open for what you really need. A PHP script that sleeps between queries should use a short wait window or reconnect on error rather than holding a socket. In PHP, catching the "gone away" exception and re-executing the query with
mysqli/PDOreconnection is the standard pattern. - Fix the restart. Check
dmesg/journalctlfor memory or crash and the MySQL log for a cleanshutdown. If the server restarts under load, the memory limit and hosting configuration are the next layer, plus reviewing what cron jobs run at that hour. Long cron jobs with a single query bigger than the defaults are the most common recurrence: give them a session with a raised budget instead of raising globals for the whole server. - Verify no firewall or proxy sits between. On a separate DB host, a load balancer or firewall with a
TCP keepaliveshorter thanwait_timeoutcloses the connection first, so the fix is on the network, not MySQL. The how to read an error log article explains mapping the line to the layer.
Prevention
- Set
wait_timeoutandmax_allowed_packetin the MySQL config file, not just the session, and write them in the host setup docs so a fresh instance reproduces them. - Keep the application's connections lazy: use a pool, reconnect on a new request, and close queries when done.
- Extract long jobs (imports, exports, cron heavy writes) into a separate process that opens its own connection and sets its own limits, and alert when those time out.
- After a host migration, compare the
my.cnfof the old host against the new before going live; the defaultmax_allowed_packetcan differ by an order of magnitude between hosts, silently breaking the big queries that worked before.
When the error comes alongside "Cannot get the value from the server" or other wrappers, the read of a PHP/MySQL log line is the fastest route to the fix. The database connection error article covers the sibling failure where the server simply refuses the connection at all.