[{"data":1,"prerenderedAt":6},["ShallowReactive",2],{"post-content-mysql-server-has-gone-away-error-2006":3},{"content":4,"lastModified":5},"\u003Cp>Three nights in a row, the same import job died at the same table. \u003Ccode>Error 2006: MySQL server has gone away\u003C\u002Fcode>, always a few hundred thousand rows in. No crash, no stack trace, the job just stopped and walked away. If you have ever stared at that message and started guessing at fixes, this is the order I check things in now, after finally nailing ours.\u003C\u002Fp>\n\n\u003Ch2>What the error actually means\u003C\u002Fh2>\n\n\u003Cp>It is less mysterious than it sounds. The client tried to send a query and the TCP connection it thought it was holding had already died. MySQL did not necessarily crash. Something between the client and the server, or a timeout on the server itself, closed the socket and nobody told your code. Its sibling, error 2013, \"Lost connection to MySQL server during query\", shares most of the same root causes, so this checklist covers both.\u003C\u002Fp>\n\n\u003Ch2>First suspect: max_allowed_packet\u003C\u002Fh2>\n\n\u003Cp>This one was ours. MySQL refuses any single packet bigger than max_allowed_packet, and instead of a friendly message about your INSERT being too big, it drops the connection on the spot. One enormous multi-row INSERT into a table with fat JSON columns was enough to do it.\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode class=\"language-sql\">SHOW VARIABLES LIKE 'max_allowed_packet';\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>MySQL 8.0 ships a 64MB server default, but the mysql command-line client keeps its own 16MB limit unless you raise it, and some distro builds and MariaDB packages go lower. The server value and the client value are two different numbers, which is why \"I already raised it\" so often turns out to mean you raised only one of them.\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode class=\"language-sql\">SET GLOBAL max_allowed_packet = 268435456; -- 256MB, applies to new connections\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>That buys you a fix without a restart, but it vanishes the next time the server restarts, so put it in my.cnf under \u003Ccode>[mysqld]\u003C\u002Fcode> as well. For dumps, raise both ends while you are at it:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode class=\"language-bash\">mysqldump --max_allowed_packet=512M --single-transaction --quick mydb &gt; dump.sql\nmysql --max_allowed_packet=512M -u myuser -p mydb &lt; dump.sql\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>If one table still kills the import, the dump probably contains a single absurdly wide multi-row INSERT. Re-dump with \u003Ccode>--extended-insert=FALSE\u003C\u002Fcode>. The file gets bigger and the import runs slower, but no single statement gets near the ceiling. And run it inside tmux, because a dropped SSH session produces the exact same 2006, caused by your own wifi.\u003C\u002Fp>\n\n\u003Ch2>Second suspect: wait_timeout and idle kills\u003C\u002Fh2>\n\n\u003Cp>If the error shows up first thing in the morning, or in a background worker that sits quiet between jobs, you are probably looking at an idle connection that got reaped. wait_timeout defaults to 28800 seconds, which is 8 hours, but load balancers, NAT gateways and cloud firewalls routinely drop idle TCP connections after 5 to 15 minutes, and they do it silently.\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode class=\"language-sql\">SHOW VARIABLES LIKE 'wait_timeout';\nSHOW GLOBAL STATUS LIKE 'Aborted_clients';\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>Aborted_clients counts connections that died without the client closing them properly. If that counter climbs in step with your errors, something is cutting sockets, and the timeout variables tell you whether it is MySQL or the plumbing in front of it. The fix is to keep the pool's idle timeout below the infrastructure's, and to turn on TCP keepalive in your client. I covered the pool arithmetic side of this in the \u003Ca href=\"\u002Fposts\u002Fmysql-too-many-connections-pool-math\u002F\">max_connections piece\u003C\u002Fa>.\u003C\u002Fp>\n\n\u003Ch2>Third suspect: the sneaky timeout pair\u003C\u002Fh2>\n\n\u003Cp>net_read_timeout and net_write_timeout are the two most people miss. A query can finish well inside wait_timeout and still get cut off while a huge result set streams back, because net_write_timeout, 60 seconds by default, governs the trip out to the client. If the error only fires on your biggest reports, raise both:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode class=\"language-sql\">SET GLOBAL net_read_timeout = 120;\nSET GLOBAL net_write_timeout = 120;\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Fourth suspect: the server actually died\u003C\u002Fh2>\n\n\u003Cp>Sometimes \"gone away\" is literal. The OOM killer took mysqld, or the process crashed. Check the service state and the error log before you touch any config:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode class=\"language-bash\">systemctl status mysql\ngrep -iE 'out of memory|killed' \u002Fvar\u002Flog\u002Fmysql\u002Ferror.log\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>If those timestamps line up with your 2006s, no amount of packet tuning will save you. The box needs RAM, or the query needs to stop holding that much in memory. One caveat on the app side: modern PHP dropped automatic reconnect, so the retry logic belongs in your code, not in an ini setting.\u003C\u002Fp>\n\n\u003Ch2>If this is WordPress\u003C\u002Fh2>\n\n\u003Cp>A large share of pages ranking for this error still tell you to edit \u003Ccode>wp-includes\u002Fwp-db.php\u003C\u002Fcode>. Skip that advice. The file has been deprecated since WordPress 6.1 and any core edit gets wiped by the next update anyway. Repair the tables if they are corrupted, then find the query that is actually too big with Query Monitor. Nine times out of ten it is a bloated \u003Ccode>wp_options\u003C\u002Fcode> table or a backup plugin dumping the database inside a web request:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode class=\"language-sql\">SELECT SUM(LENGTH(option_value)) FROM wp_options WHERE autoload = 'yes';\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>Worry once that number clears a megabyte.\u003C\u002Fp>\n\n\u003Ch2>The order I check now\u003C\u002Fh2>\n\n\u003Cp>Packet size first, then wait_timeout and its friends, then the network gear in between, then the server itself. I keep these four queries in \u003Ca href=\"\u002Fsnippetark\u002F\">Snippet Ark\u003C\u002Fa>, because retyping \u003Ccode>SHOW VARIABLES LIKE '%timeout%'\u003C\u002Fcode> from memory twice a year is exactly how the guessing starts.\u003C\u002Fp>\n","2026-10-21",1793106023374]