"MySQL server has gone away" is client error 2006. It means the client tried to use a connection that no longer works. The error tells you nothing about why the connection is gone. The MySQL manual lists more than ten possible causes, from an idle timeout to a server crash, and the fix for one is useless for another. So the first job is not to change a setting but to find out who closed the connection.
2006, 2013 and 4031: three faces of the same problem
ERROR 2006 (HY000): MySQL server has gone away
ERROR 2013 (HY000): Lost connection to MySQL server during query
ERROR 4031 (HY000): The client was disconnected by the server because of inactivity.
See wait_timeout and interactive_timeout for configuring this behavior.
- 2006 (
CR_SERVER_GONE_ERROR): according to the manual, the client could not send a question to the server. - 2013 (
CR_SERVER_LOST): the client did not get an error when writing to the server, but did not get a full answer, or any answer. The manual notes that which of the two you get for a server-side timeout depends on the operating system, so treat them as one family. - 4031 (
ER_CLIENT_INTERACTION_TIMEOUT): added in MySQL 8.0.24. When the server closes a connection because it was idle longer thanwait_timeout, it now writes the reason to the connection first, so the client sees this clearer message. The release notes add that the old behavior still applies to older servers and older clients, so on mixed setups you can still see 2006 or 2013 for a plain idle timeout.
If you see 4031, you can skip most of this article: the connection sat idle too long. If you see 2006 or 2013, keep reading.
Step 1: collect four facts
Before changing anything, run this on the server:
SHOW GLOBAL VARIABLES WHERE Variable_name IN
('wait_timeout', 'interactive_timeout', 'max_allowed_packet',
'net_read_timeout', 'net_write_timeout', 'connect_timeout');
SHOW GLOBAL STATUS WHERE Variable_name IN
('Uptime', 'Aborted_clients', 'Aborted_connects');
Then answer four questions:
- Did the server restart? Compare
Uptimewith the time of the errors. The manual suggests exactly this check: if the connection broke because mysqld crashed and restarted, the error is the least of your problems and the crash is what to investigate. Check the error log. - How long had the connection been idle? If the failing request is the first one after a quiet period (overnight jobs, a worker that wakes up once an hour, a connection pool after a weekend) and the gap is longer than the session's
wait_timeout, you have found it. - How big was the request? A huge
INSERT, a largeBLOBor a long generated query points atmax_allowed_packet. - Did someone or something kill the session? A
KILLfrom a DBA, a monitoring script that kills long queries, or a failover tool all look identical from the client side.
The manual also suggests starting mysqld with log_error_verbosity set to 3 to log some of the disconnection messages in the error log, which helps when the client side tells you nothing.
Cause 1: the connection was idle longer than wait_timeout
This is the cause the manual calls the most common one. By default the server closes a connection after eight hours without activity: wait_timeout and interactive_timeout both default to 28800 seconds.
There is a trap in how these two interact. Per the server variables reference, when a session starts, its wait_timeout is initialized from the global wait_timeout or from the global interactive_timeout, depending on whether the client connected with the CLIENT_INTERACTIVE option. Changing only one of the two globals therefore may not affect the connections you care about. Check what the session really got:
-- what THIS session actually got (may differ from the global value)
SELECT @@SESSION.wait_timeout, @@GLOBAL.wait_timeout, @@GLOBAL.interactive_timeout;
Teams that lowered wait_timeout to clean up idle connections, which our article on "Too many connections" suggests considering, sometimes forget the application side. If the connection pool keeps connections longer than the server does, the pool will eventually hand out a dead one.
The fix belongs in the application, not in a bigger timeout:
- Set the pool's maximum connection lifetime or idle time below the server's
wait_timeout, so the pool retires connections before the server does. - Enable the pool's connection validation (a test query or ping before handing out a connection that has been idle), if your pool supports it.
- For long-running scripts, open the connection when you need it, not at startup.
Do not forget what sits between the application and MySQL. Load balancers, proxies, NAT gateways and firewalls can have their own idle timeouts and silently drop TCP connections that MySQL still considers open. If wait_timeout is eight hours but connections die after a few minutes of silence, look at the network path.
Cause 2: the packet was too large
From the "Packet Too Large" page: when a MySQL client or the mysqld server receives a packet bigger than max_allowed_packet bytes, it issues an ER_NET_PACKET_TOO_LARGE error (1153, "Got a packet bigger than 'max_allowed_packet' bytes") and closes the connection. Some clients only show you the closed connection, which is why this often appears as 2006 or 2013.
Key numbers from the manual:
- The server default for
max_allowed_packetis 64MB. - The
mysqlclient program has its own default of 16MB. - The largest possible packet to or from a MySQL 8.4 server or client is 1GB.
Both sides have their own variable, so a large import may need the setting raised on the client as well as the server:
[mysqld]
max_allowed_packet = 128M
# and on the client side, for example:
# mysql --max_allowed_packet=128M
Before raising it, check whether you need to. The manual points out that an INSERT or REPLACE with a great many rows is sent as a single request, and you can often avoid the error by sending fewer rows per statement. Smaller batches are usually easier on the server, on replication and on your retry logic than one giant statement.
Cause 3: the query or result took too long on the wire
The lost connection page covers the 2013 variant. If the message includes "during query", the manual says network trouble is the likely cause. It also describes a case where millions of rows are being sent and suggests increasing net_read_timeout from its default of 30 seconds to 60 seconds or longer. Its sibling net_write_timeout defaults to 60 seconds and controls how long the server waits when writing to the client. A client that reads a huge result set slowly, for example processing each row before fetching the next, can run into it.
Client-side timeouts matter too. The manual mentions the C API read and write timeout options; most drivers have equivalents. If the driver gives up after 30 seconds on a query that takes 40, the result looks like a lost connection even though the server is fine.
For errors at connect time, the manual points to connect_timeout (default 10 seconds) and to the Aborted_connects status counter, which increases by one for each initial connection attempt the server aborts. "reading authorization packet" in the message is a hint in that direction.
Cause 4: the session was killed or the server went down
The manual lists a KILL statement or mysqladmin kill as a cause. In practice this includes tools that kill long-running queries automatically, which is worth checking if errors cluster around heavy reports. Our lock wait timeout guide shows how to find blocking sessions, which are a common reason someone reaches for KILL in the first place.
A server crash, an OOM kill or a failover to a replica also ends every connection. If Uptime is short, start with the error log and the system log, not the client.
Cause 5: bugs in the application's connection handling
Two causes from the manual come straight from application code:
- Using a connection after closing it. The manual calls this a logic error in the application that should be corrected.
- Forked processes sharing one connection. Applications that fork child processes which all use the same MySQL connection can get these errors. The fix is a separate connection per child process. Watch for this with pre-forking web servers and job runners that open the connection before forking.
GET_LOCK() locks are released, temporary tables are dropped, session variables and user variables are lost, and LAST_INSERT_ID() resets to 0. Code that silently reconnects in the middle of a transaction can carry on as if half its work was not just thrown away. Reconnect, then restart the whole unit of work.Use Aborted_clients as an early warning
The communication errors page explains that when a client connects successfully but later disconnects improperly or is terminated, the server increments Aborted_clients and logs an "Aborted connection" message. Causes include a client exiting without closing the connection, a client sleeping longer than wait_timeout or interactive_timeout, a client ending in the middle of a data transfer, a too-small max_allowed_packet, and faulty network hardware. Graph the counter. A steady trickle is normal for many applications; a sudden increase after a deploy or a network change tells you where to look before users start reporting errors.
Key takeaways
- Errors 2006 and 2013 only say the connection is gone. Since 8.0.24, an idle timeout is reported as the clearer error 4031 when both client and server support it.
- Check
Uptime, idle time, request size and recentKILLs before changing settings. - For idle timeouts, make the pool retire connections before the server's
wait_timeout, and remember that the session value may come frominteractive_timeout. - For large requests, split batches first; if you raise
max_allowed_packet(server default 64MB,mysqlclient 16MB, maximum 1GB), raise it on both sides. - Auto-reconnect resets session state and rolls back open transactions without telling the application. Restart the whole unit of work after a reconnect.