ERROR 2006 (HY000): MySQL server has gone away or its close relative ERROR 2013 (HY000): Lost connection to MySQL server during query. The usual advice is to raise max_allowed_packet and wait_timeout together and try again. Sometimes that works, but it hides which limit actually tripped. One of the most common causes is neither setting: the MySQL process itself died and restarted halfway through.
This guide is about collecting evidence first. Each cause leaves different traces, and you can check all of them from the command line in a few minutes.
What the error actually tells you
- The server rejected a statement because it was bigger than
max_allowed_packetand closed the connection. - The connection sat idle longer than
wait_timeout, and the server dropped it. mysqldcrashed or was killed, often by the kernel's OOM killer (the out-of-memory killer, which terminates a process when RAM and swap run out), and the client lost its connection along with everything else.- Something in between, such as a proxy or firewall, cut the connection.
Step one: rule out a restart or an OOM kill
BASH
# Uptime in seconds. If it is shorter than the import ran, mysqld restarted mid-import.
mysqladmin status
# Where the server writes its error log
mysql -N -e 'SELECT @@log_error'
# Kernel messages about OOM kills in the last few hours
journalctl -k --since '3 hours ago' | grep -iE 'out of memory|killed process'
# Service state and recent restarts (service name may be mysql, mysqld, or mariadb)
systemctl status mysqlUptime is only a few minutes and the kernel log shows Killed process with mysqld or mariadbd in it, you have your answer. The import pushed memory over the edge, or something else on the box did and MySQL was the process the kernel chose. Why the kernel tends to pick MySQL over processes that look hungrier is covered in Kenapa OOM Killer Mematikan MySQL, Bukan Proses yang Paling Boros Memori.
If there is no OOM message but uptime is still short, open the error log path from the second command and read the last lines before the restart. A crash usually leaves a stack trace or an assertion message there. A clean restart from a cron job or a panel action looks like a normal shutdown sequence.
If uptime is long and there is no kill in the kernel log, the server stayed up and closed the connection on purpose. That points to the two limits in the title.
Step two: check max_allowed_packet against the dump
mysqldump uses extended inserts by default: one INSERT statement carries many rows at once. One of those lines can easily reach tens of megabytes, especially for tables with BLOB or long TEXT columns, or tables full of serialized data like WordPress options or page builder content.
The limit exists on both sides. The server has its own max_allowed_packet, and so does the client doing the import. Either one can reject the statement. Compare what the server allows with the largest statement in the file:
BASH
# Server-side limits, in bytes and seconds
mysql -N -e 'SELECT @@global.max_allowed_packet, @@global.wait_timeout, @@global.interactive_timeout, @@global.net_read_timeout'
# Longest line in the dump, in bytes (LC_ALL=C makes awk count bytes, not characters)
LC_ALL=C awk '{ if (length(0) > max) max = length(0) } END { print max }' dump.sql
# Same check for a gzipped dump, without unpacking it to disk
zcat dump.sql.gz | LC_ALL=C awk '{ if (length(0) > max) max = length(0) } END { print max }'mysqldump writes each extended insert as one line. If that number is larger than the server's max_allowed_packet, you have found a real problem regardless of what else is going on.
The error log confirms it, if the server logs aborted connections. That depends on log_error_verbosity in MySQL 8 or log_warnings in MariaDB and older MySQL, so the line might not be there on a default setup. When it is, it looks roughly like this:
TEXT
# Illustrative output format (exact wording and prefixes vary by version)
Aborted connection 1234 to db: 'shopdb' user: 'shopuser' host: 'localhost' (Got a packet bigger than 'max_allowed_packet' bytes)
Aborted connection 1240 to db: 'shopdb' user: 'shopuser' host: 'localhost' (Got timeout reading communication packets)wait_timeout on an idle connection or net_read_timeout when the client stopped sending in the middle of a statement.
Step three: decide whether wait_timeout is even plausible
wait_timeout only applies to idle connections, ones where the server is waiting for the next command. A plain mysql dbname < dump.sql import sends statements continuously, so the connection is almost never idle long enough to hit it. If the import failed on a big statement after running steadily, wait_timeout is an unlikely suspect.
It becomes the real cause in a different pattern: a script that connects, does something slow without touching the database, then comes back to query. Examples include a PHP migration script that processes files or calls an external API between queries, a long cron job that holds one connection for its whole run, or a persistent connection that sits in a pool overnight. The query after the long pause hits a connection the server has already closed.
You can reproduce this behavior safely in a test session. Open the mysql client, run SET SESSION wait_timeout = 10;, wait about 20 seconds, then run SELECT 1;. The client reports that the connection was lost and, by default, tries to reconnect. Keep in mind that the session value can come from interactive_timeout instead of wait_timeout for interactive clients, so check SELECT @@session.wait_timeout; from the same kind of client your script uses rather than assuming the global value applies.
The evidence usually lines up like this:
| Evidence | Likely cause |
|---|---|
Short Uptime, Killed process in kernel log | OOM kill of mysqld |
Short Uptime, no OOM message, stack trace in error log | Crash, needs separate investigation |
Long uptime, longest dump line > max_allowed_packet | Packet limit |
| Long uptime, failure after a pause in a script, timeout message in log | wait_timeout (or interactive_timeout) |
| Long uptime, timeout message during a slow or remote pipe | net_read_timeout or the network path |
Making the change and proving it worked
SET GLOBAL max_allowed_packet = ... takes effect only for new connections, and it is lost when the server restarts. To make it permanent, set it under [mysqld] in the server config file, whose location depends on the distro and on whether a control panel manages it. Raise the client side too, for example mysql --max_allowed_packet=256M dbname < dump.sql. The value 256M here is an illustrative example. Size it to the longest line you measured plus some headroom. The protocol caps it at 1GB, and a very large value lets a single connection allocate a lot of memory, so going higher than you need is not free.
On shared hosting you usually cannot touch global settings. The practical fix there is on the dump side: re-export with mysqldump --net-buffer-length=... to keep each extended insert smaller, or with --skip-extended-insert to write one row per statement. Both work. The second makes the file larger and the import slower.
For wait_timeout, the better fix is often in the script rather than the server: reconnect or ping the connection before using it after long work, or open the connection only when you need it. Raising the global timeout keeps every idle connection on the server alive longer, which can use up max_connections on a busy host.
For an OOM kill, neither setting helps. Reduce memory pressure during the import: stop or limit other heavy processes, check whether InnoDB buffer pool and per-connection buffers fit the RAM you actually have, or move to a plan with more memory.
After the change, verify instead of assuming. Re-run the variable query and confirm the new value shows for a fresh connection. Re-run the import and check mysqladmin status afterward to confirm uptime kept counting through it. Look at the Aborted_clients counter in mysqladmin extended-status before and after: if it still climbs during the import, something is still closing connections.
The short version: when you see "gone away", check uptime and the kernel log before you touch any config. If the server stayed up, measure the biggest statement in the dump and compare it with max_allowed_packet on both server and client. Treat wait_timeout as a suspect only when there is an actual idle gap. Each of these leaves evidence, and five minutes of reading it saves several rounds of guessing and re-importing.