MySQL Server Has Gone Away Error: 7 Fixes (2026)
Fix MySQL server has gone away error by comparing packet size limits, timeout tweaks, and connection pooling. Choose the right solution for your workload.

On this page
- Why MySQL Disconnects Mid-Query
- Fix 1: Increase max_allowed_packet for Large Queries
- Fix 2: Adjust wait_timeout and interactive_timeout
- Fix 3: Implement Connection Pooling with Health Checks
- Fix 4: Split Large Queries into Batches
- Fix 5: Check Network Stability and MTU Settings
- Comparing the Seven Fixes: Which One to Apply
- Verifying the Fix and Monitoring for Recurrence
TL;DR — Key takeaways
- Error 2006 typically stems from packet size limits (max_allowed_packet), idle timeouts (wait_timeout), or dropped connections during long queries
- Increasing max_allowed_packet to 64M or higher solves most large query and BLOB upload failures
- Connection pooling with proper health checks prevents timeout issues better than raising wait_timeout alone
- Always test changes on a staging environment and monitor slow query logs to identify the root cause before applying production fixes
You run a query. MySQL vanishes mid-execution. Error 2006: MySQL server has gone away. The connection dropped, the data didn't save, and your application logs fill with stack traces.
This error hits during large imports, file uploads, or idle connection scenarios. The fix depends on whether you're hitting packet size limits, timeout thresholds, or network stability issues. I've walked through this with dozens of support tickets where the solution was one configuration line—but only after identifying which limit was actually breaking.
Why MySQL Disconnects Mid-Query
MySQL terminates connections when client requests exceed its safety boundaries. Three server variables control these limits: max_allowed_packet caps single query size, wait_timeout closes idle connections, and net_read_timeout kills slow data transfers.
The default max_allowed_packet of 4MB stops most BLOB inserts and CSV imports cold. When your application sends a 10MB image or a bulk INSERT with 50,000 rows, the server drops the connection instead of processing it. You'll see error 2006 in application logs with no corresponding entry in MySQL's error log—because from MySQL's perspective, it's enforcing policy, not crashing.
Idle timeouts work differently. If your application opens a connection, runs a query, then waits 8+ hours before the next operation (default wait_timeout is 28800 seconds), MySQL closes the socket. The application doesn't know until it tries to send the next query. Connection pools mitigate this, but only if configured to send keepalive pings shorter than wait_timeout.
Fix 1: Increase max_allowed_packet for Large Queries
The tradeoff: memory allocation scales with this value times max_connections. If you set 256M and allow 200 connections, MySQL reserves up to 51GB just for packet buffers (though it only allocates per active connection). Monitor actual memory usage with top or htop after the change.
In my experience handling storage-heavy WordPress sites, 64M solves 90% of media upload failures without threatening server stability. Go higher only if you're processing data dumps or video transcoding metadata.
- Set max_allowed_packet = 64M for typical BLOB storage and CSV imports
- Use 256M or higher for video file metadata or analytics batch inserts
- Restart MySQL with systemctl restart mysql or service mysql restart
- Verify the change took effect: mysql -e "SHOW VARIABLES LIKE 'max_allowed_packet';"
Fix 2: Adjust wait_timeout and interactive_timeout
Raising wait_timeout above 1 hour creates a vulnerability: abandoned connections consume memory and connection slots until they expire. A better pattern is keeping timeouts short (10-15 minutes) and configuring your application's connection pool to refresh connections proactively.
For PHP applications using PDO or MySQLi, enable persistent connections and set PDO::ATTR_TIMEOUT to 30 seconds. For Node.js with mysql2, configure waitForConnections: true and connectionLimit based on your traffic patterns.
- Set wait_timeout = 600 (10 minutes) for web applications with proper connection pooling
- Use interactive_timeout = 3600 (1 hour) to keep admin shell sessions alive during manual operations
- Add these under [mysqld] in my.cnf, not in a session-level SET command
- Always pair timeout increases with application-side connection validation
Fix 3: Implement Connection Pooling with Health Checks
Pools prevent the reconnection overhead that kills performance during traffic spikes. Without pooling, every request opens a new socket, authenticates, and closes on completion. That's 5-10ms per request. Pooled connections drop that to under 1ms.
- In Laravel, set 'options' => [PDO::ATTR_PERSISTENT => true] in config/database.php to enable persistent connections
- For Node.js mysql2, use createPool() with connectionLimit: 10 and configure acquireTimeout less than wait_timeout
- Java applications with HikariCP should set maxLifetime to 30000 (30 seconds less than wait_timeout) and connectionTimeout to 20000
- Monitor pool exhaustion with application metrics—if you're hitting maxConnections frequently, scale horizontally before raising limits
Fix 4: Split Large Queries into Batches
The 500-1000 row sweet spot comes from testing across hosting environments. Smaller batches waste CPU on network overhead; larger ones risk hitting max_allowed_packet even after raising it. Measure your average row size in bytes and calculate batch size to stay under 80% of max_allowed_packet.
- Use LIMIT and OFFSET for SELECT operations: process 5,000 rows at a time, sleep 100ms between batches to avoid replication lag
- For INSERTs, build multi-row INSERT statements with 500-1000 rows each (balance between network round trips and packet size)
- Wrap batches in transactions when order matters: START TRANSACTION, run batch, COMMIT; roll back on errors
- Laravel's chunk() method handles this automatically: DB::table('users')->orderBy('id')->chunk(1000, function ($users) { /* process */ });
Fix 5: Check Network Stability and MTU Settings
I've seen this on hybrid cloud setups where the application runs in AWS and the database sits on-premises. The VPN tunnel's idle timeout was 5 minutes, shorter than MySQL's wait_timeout. Connections died mid-query because the network equipment dropped the socket, not MySQL.
- Ping the MySQL server with large packets: ping -s 8192 -c 100 <db-server-ip> and check for packet loss
- Verify MTU settings match across network interfaces: ip link show on Linux, check that MySQL server and app server use the same value (typically 1500 or 9000 for jumbo frames)
- If using a cloud load balancer or proxy, check its idle timeout setting—AWS NLB defaults to 350 seconds and silently drops idle TCP connections
- Run tcpdump during a failure to capture the actual TCP RST or FIN packets: tcpdump -i any -s 0 -w mysql-debug.pcap port 3306
Comparing the Seven Fixes: Which One to Apply
Test changes on a staging clone of your production database. Apply one fix at a time and monitor error rates for 24 hours before adding another. If you stack three config changes and the error stops, you won't know which one actually mattered—and you might be wasting resources on an unnecessary setting.
- For WordPress, WooCommerce, or Magento: increase max_allowed_packet to 64M, enable persistent connections in wp-config.php or app/etc/env.php
- For Laravel, Django, or Rails: configure connection pooling first, then raise max_allowed_packet if BLOB uploads still fail
- For data import scripts or ETL jobs: batch your inserts to 500-1000 rows per statement and sleep 100ms between batches
- For intermittent errors with no clear pattern: check network path, verify MTU settings, and inspect firewall/load balancer idle timeouts
Verifying the Fix and Monitoring for Recurrence
In support tickets I handled, the usual culprit was a full disk preventing MySQL from writing temp tables during large JOINs. The error message said 'server has gone away,' but df -h showed /var at 100%. Always check disk space and inode usage (df -i) before diving into configuration.
- Monitor connection count in real time: watch -n 1 'mysql -e "SHOW STATUS LIKE \"Threads_connected\";"'
- Check for aborted connections (symptom of timeout issues): mysql -e "SHOW STATUS LIKE 'Aborted_connects';"
- Set up application-level metrics for database error rates—track error 2006 specifically so you catch regressions immediately
- Review MySQL's performance schema if available (MySQL 5.6+): query performance_schema.events_statements_summary_by_digest for slow or failing patterns
Quick troubleshooting checklist
- Check current max_allowed_packet value with SHOW VARIABLES LIKE 'max_allowed_packet'
- Review error logs at /var/log/mysql/error.log for dropped connection details
- Test packet size increase on staging server before production deployment
- Enable slow query log to identify queries exceeding timeout thresholds
- Verify application connection pool settings match server timeout values
- Restart MySQL service after configuration changes to my.cnf
- Monitor application error rates for 24 hours after applying fixes
FAQ
What causes MySQL server has gone away error?
The error occurs when MySQL closes a connection due to exceeding max_allowed_packet size (default 4MB), idle timeout expiration (wait_timeout default 28800 seconds), or network interruptions during query execution. Large INSERT statements, BLOB uploads, and long-running queries are common triggers.
Should I increase max_allowed_packet or wait_timeout first?
Increase max_allowed_packet first if you see the error during large data operations or file uploads. Only raise wait_timeout if application logs show idle connection timeouts. Setting max_allowed_packet to 64M solves most cases without the security risk of keeping idle connections open longer.
How do I fix MySQL server has gone away in Laravel?
Set DB_TIMEOUT in .env to match your server's wait_timeout, enable persistent connections with 'options' => [PDO::ATTR_PERSISTENT => true] in config/database.php, and increase max_allowed_packet on the MySQL server. Laravel's database reconnection logic handles most timeout cases automatically if configured correctly.
Related articles
- Hosting OperationsSelf-Hosted App Deployment Fails? Check DNS, SSL, Reverse Proxy, and Logs FirstTroubleshoot failed self-hosted app deployments by checking DNS, SSL, reverse proxy routing, container status, logs, and ports.
- Hosting OperationsSelf-Hosted PaaS on a VPS: What to Check Before Installing Coolify, Dokploy, or CapRoverA hosting support checklist for preparing a VPS before installing self-hosted PaaS tools like Coolify, Dokploy, or CapRover.
- Hosting OperationsLinux Server Security Lessons from the Arch Linux Malware Package IncidentPractical Linux server security checklist for VPS admins after package malware concerns, with safe checks, rollback steps, and support guidance.
- Hosting OperationsAWS Lightsail Hong Kong VPS Latency: Practical Hosting Guide for IndonesiaLearn how to test AWS Lightsail Hong Kong VPS latency, compare regions, migrate safely, and troubleshoot hosting performance.
- Hosting OperationsCloudflare Tomorrow Watchlist: A Practical Hosting Operations GuidePractical Cloudflare troubleshooting checklist for DNS, SSL, caching, WAF, origin health, safe testing, and rollback planning.
- Hosting OperationsNetwork Safety Checklist for AI Agent Skills in Hosting OperationsAudit AI agent skills safely with network checks, secret protection, sandbox testing, rollback steps, and hosting support troubleshooting guidance.