MySQL Server Has Gone Away: Causes and How to Fix It
You're mid-import, or your WordPress site suddenly throws a database error, and the log says: MySQL server has gone away. Nothing looks obviously broken - the site loads fine a second later. That's the confusing part. This error isn't really about MySQL crashing (though it can be); most of the time it's about a connection that sat idle too long, or a query that was simply too big for MySQL to accept.
What This Error Actually Means
"MySQL server has gone away" means the PHP process (or mysql client) had an open connection to MySQL, and by the time it tried to use that connection, MySQL had already closed it. The client didn't get a graceful error - it just found the socket dead. There are really only four reasons this happens:
- The connection sat idle longer than MySQL's
wait_timeout, so MySQL closed it server-side. - The query (or a piece of data in it, like a base64 image or a large post body) exceeded
max_allowed_packet. - MySQL itself restarted, crashed, or got killed by the OOM killer mid-request.
- A network blip or firewall/proxy timeout dropped the TCP connection (common with remote MySQL over the internet).
Cause 1: wait_timeout Killed an Idle Connection
This is the most common cause on shared hosting and cPanel VPS setups. MySQL closes any connection that's been idle longer than wait_timeout (default is 28800 seconds / 8 hours on most installs, but cPanel/CloudLinux tunes it much lower - often 60-300 seconds - to stop idle connections piling up under CloudLinux's LVE limits).
You'll hit this when:
- A long-running PHP script opens a DB connection, does something slow (like calling an external API), then tries to write to the database again.
- A cron job or WP-Cron task holds a connection open between queries.
- Persistent connections (
mysqliwith thep:prefix, or oldmysql_pconnect) get reused after sitting idle across requests.
Check the current value in WHM > MySQL/MariaDB Configuration, or via SSH:
mysql -u root -p -e "SHOW VARIABLES LIKE 'wait_timeout';"
Fix It
Don't just crank wait_timeout up - fix the code path holding the connection open where you can, and raise the timeout modestly as a safety net.
# In /etc/my.cnf (or /etc/mysql/mariadb.conf.d/50-server.cnf)
[mysqld]
wait_timeout = 300
interactive_timeout = 300
# Restart after editing
systemctl restart mysql # or mariadb, or via WHM MySQL Configuration
On shared cPanel hosting you usually can't touch my.cnf directly - use WHM > MySQL/MariaDB Configuration > Config Editor, or ask support to raise it for your account. In WordPress specifically, avoid holding a DB connection open across a slow wp_remote_get() call - do the external call first, then touch the database.
Cause 2: max_allowed_packet Is Too Small
This one shows up as "gone away" the moment you try to insert or update something large - a big serialized options row, a base64-encoded image pasted into a post, or a bulk INSERT during a database import. MySQL rejects the packet outright and drops the connection instead of returning a clean "too large" error, which is exactly what makes this cause confusing.
Check the current limit:
mysql -u root -p -e "SHOW VARIABLES LIKE 'max_allowed_packet';"
Default is often 4 MB or 16 MB depending on the MySQL/MariaDB version. If you're importing a large .sql dump via phpMyAdmin or SSH and it fails partway through with this error, this is almost always the cause.
Fix It
# /etc/my.cnf
[mysqld]
max_allowed_packet = 256M
[mysqldump]
max_allowed_packet = 256M
systemctl restart mysql
For a one-off import over SSH without editing the config file:
mysql --max_allowed_packet=256M -u dbuser -p dbname < dump.sql
On managed cPanel hosting, raise it through WHM > MySQL/MariaDB Configuration, or import via SSH with the flag above instead of phpMyAdmin, which has its own upload and memory ceilings on top of this one.
Cause 3: MySQL Actually Crashed or Restarted
Sometimes the server really did go away. On a VPS with limited RAM, MySQL is a common target for the Linux OOM killer when memory runs out - it gets killed to free up memory, then usually auto-restarts via systemd, but any connection open at that moment breaks with this exact error.
Check for this specifically:
# OOM kill evidence
dmesg | grep -i "killed process" | grep -i mysql
grep -i "oom" /var/log/syslog
# MySQL's own error log - look for a recent restart
tail -100 /var/log/mysql/error.log
# or on cPanel:
tail -100 /var/lib/mysql/$(hostname).err
If you see MySQL restarting on its own repeatedly, it's not a config tweak you need - it's more RAM, less concurrent load, or a lower innodb_buffer_pool_size. See our guide on diagnosing OOM kills and adding swap if this is happening on a VPS.
Cause 4: Remote MySQL Over an Unstable Network
If your app connects to a MySQL server on a different machine (a separate database server, or an app hosted elsewhere connecting back to cPanel's Remote MySQL feature), a firewall, load balancer, or NAT gateway between the two can silently drop idle TCP connections well before MySQL's own wait_timeout kicks in. The app has no idea the socket died until it tries to use it.
Fix It
- Enable TCP keepalive on the client side so idle connections send periodic probes instead of going silent.
- Lower your app's own connection-pool idle timeout below whatever the network path enforces (test both 60s and 300s).
- Wrap DB calls in reconnect logic - most drivers (PDO, mysqli, ORMs like Laravel's Eloquent) support automatic reconnect-on-lost-connection; turn it on rather than hand-rolling retries.
Quick Reference Table
| Symptom | Likely Cause | Fix |
|---|---|---|
| Fails after the site sits idle, then works on reload | wait_timeout | Raise wait_timeout, avoid holding connections open across slow calls |
| Fails only on large imports or big post content | max_allowed_packet | Raise max_allowed_packet in my.cnf and mysqldump section |
| Fails randomly, MySQL error log shows a restart | OOM kill / crash | Add RAM/swap, lower innodb_buffer_pool_size, check for OOM kills |
| Only happens on remote/cross-server DB connections | Network/firewall idle timeout | TCP keepalive, shorter pool idle timeout, reconnect logic |
Prevention
- Enable auto-reconnect in your database driver instead of relying on the connection never dropping.
- Keep long-running scripts (imports, migrations, bulk cron jobs) reconnecting periodically rather than holding one connection for the whole run.
- Monitor MySQL's error log for unexpected restarts - a single "gone away" report is a config tweak, a recurring one is a resource problem.
- If you manage your own VPS, keep
innodb_buffer_pool_sizesized to leave headroom for PHP-FPM and the OS, not maxed out to available RAM.
Most of the time this error is a five-minute config fix once you know which of the four causes you're dealing with. Check the MySQL error log first - it'll usually tell you within a few lines whether you're looking at a timeout, a packet size limit, or an actual crash.
Frequently asked questions
Does raising wait_timeout fix this permanently?
It reduces how often you hit the error, but it treats the symptom. If a script is holding a connection open for minutes at a time, fix that code path - raising the timeout just delays the next occurrence under heavier load.
Why does this happen during a database import specifically?
Large SQL dumps often contain single INSERT statements bigger than the default max_allowed_packet (commonly 4-16MB). MySQL drops the connection instead of returning a clear error, so import via SSH with mysql --max_allowed_packet=256M rather than through phpMyAdmin.
Is this the same as 'Error establishing a database connection' in WordPress?
No. That error usually means MySQL can't be reached at all (wrong credentials, MySQL not running, or wp-config.php misconfigured). 'Gone away' means a connection was established and worked, then died mid-session.
Can a WordPress plugin cause this?
Yes - plugins that make slow external API calls (payment gateways, import tools, SMTP senders) while holding a database connection open are a common trigger, especially combined with an aggressive CloudLinux wait_timeout on shared hosting.
How do I know if it was an OOM kill versus a timeout?
Run dmesg | grep -i 'killed process' | grep -i mysql. If MySQL shows up there, it was killed for memory - that's a resource issue, not a timeout setting, and needs more RAM/swap or a smaller innodb_buffer_pool_size.