Troubleshooting ‘MySQL server has gone away: packet too large’ Query Failure on Ubuntu 20.04 LTS

Resolve the 'MySQL server has gone away: packet too large' error on Ubuntu 20.04 LTS by adjusting MySQL, PHP-FPM, and application configurations to handle large queries and result sets.


Resolve the 'MySQL server has gone away: packet too large' error on Ubuntu 20.04 LTS by adjusting MySQL, PHP-FPM, and application configurations to handle large queries and result sets.

This guide addresses a common and often frustrating issue where your application or database client encounters a MySQL server has gone away error, specifically accompanied by the "packet too large" context. This typically happens when your database client or server tries to send/receive a data packet exceeding its configured maximum size, leading to an abrupt connection termination. For administrators running web applications on Ubuntu 20.04 LTS with a MySQL or MariaDB backend, this guide provides a step-by-step resolution.

Symptom & Error Signature

Users typically experience this error when executing large SQL queries, importing substantial datasets, or fetching extensive result sets. This can manifest as:

  • Web application errors: A blank page, a generic "server error," or an explicit error message logged by the application.
  • Failed cron jobs: Scripts performing data synchronization or batch operations terminate unexpectedly.
  • Database client errors: Using the mysql command-line client or a GUI tool, the connection drops, or a query fails with the specific error.

Typical error messages you might encounter include:

1. PHP Application Error Log (e.g., in /var/log/phpX.X-fpm.log or application-specific logs):

[202X-XX-XX XX:XX:XX] production.ERROR: SQLSTATE[HY000]: General error: 2006 MySQL server has gone away {"exception":"[object] (PDOException(code: 2006): SQLSTATE[HY000]: General error: 2006 MySQL server has gone away at /var/www/html/app/src/Database.php:123)"}

Or, more explicitly:

[202X-XX-XX XX:XX:XX] production.ERROR: Error: MySQL server has gone away (packet too large) during query execution.

2. MySQL Command-Line Client Error:

ERROR 2006 (HY000): MySQL server has gone away

3. General Application Log (Python, Node.js, etc.):

DB_ERROR: (2006, "MySQL server has gone away (packet too large)")

Root Cause Analysis

The "MySQL server has gone away" error, particularly with the "packet too large" indication, fundamentally points to a mismatch or misconfiguration in the maximum allowable packet size for data exchange between the MySQL client (your application) and the MySQL/MariaDB server.

Here's a breakdown of the underlying reasons:

  1. max_allowed_packet on the MySQL/MariaDB Server: This is the most common culprit. The max_allowed_packet server variable defines the maximum size of a single packet or any generated/intermediate string, or any parameter sent by the mysql_stmt_send_long_data() C API function. If a client attempts to send a query (e.g., a very large INSERT or UPDATE statement, or a BLOB field) or the server tries to return a result set larger than this configured value, the connection is abruptly terminated.

  2. max_allowed_packet on the MySQL Client: While less common for applications (as they often inherit server settings or use a default that works), some client libraries or utilities (like the mysql command-line client) can also have their own max_allowed_packet setting. If the client's setting is lower than what the server is configured for, or if the client tries to send data larger than its own limit, the connection will drop.

  3. PHP memory_limit (for PHP Applications): When a PHP application fetches a very large result set from the database, the data must be held in the PHP script's memory. If the size of this data exceeds the configured memory_limit in php.ini, PHP will terminate the script, which can manifest as a "MySQL server has gone away" error because the PHP process drops the database connection without proper closure.

  4. Network Issues or Timeouts (General "Gone Away"): While "packet too large" specifically points to the packet size, the broader "MySQL server has gone away" can also be caused by network connectivity issues, the server crashing, or connection timeouts (wait_timeout, interactive_timeout). However, for this specific error (packet too large), these are usually secondary or unrelated.

Step-by-Step Resolution

To resolve the "MySQL server has gone away: packet too large" error, you'll primarily need to adjust configuration parameters on both your MySQL/MariaDB server and potentially your application's environment (e.g., PHP-FPM).

1. Adjust MySQL/MariaDB Server's max_allowed_packet

This is typically the most direct solution.

  1. Check the current value: Connect to your MySQL/MariaDB server using the command-line client and check the current max_allowed_packet setting:

    mysql -u root -p -e "SHOW VARIABLES LIKE 'max_allowed_packet';"
    

    You will be prompted for your MySQL root password. The output will show the value in bytes (e.g., 16777216 for 16MB).

  2. Locate the MySQL/MariaDB configuration file: On Ubuntu 20.04 LTS, MySQL and MariaDB configuration files are usually located in /etc/mysql/. Common files to modify include:

    • /etc/mysql/my.cnf (main configuration)
    • /etc/mysql/mysql.conf.d/mysqld.cnf (MySQL specific configuration)
    • /etc/mysql/mariadb.conf.d/50-server.cnf (MariaDB specific server configuration)

    It's best practice to check which file is actually being used by your server. Often, you'll find !includedir /etc/mysql/conf.d/ or !includedir /etc/mysql/mariadb.conf.d/ in my.cnf, meaning specific settings are in separate files. For server-wide settings, mysqld.cnf (MySQL) or 50-server.cnf (MariaDB) are typically the correct places.

  3. Edit the configuration file: Open the relevant configuration file with a text editor (e.g., nano or vim). For MariaDB, this might be /etc/mysql/mariadb.conf.d/50-server.cnf:

    sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf
    

    Locate the [mysqld] section and add or modify the max_allowed_packet directive. A common value for web applications is 64M or 128M, but you might need more depending on your data.

    # /etc/mysql/mariadb.conf.d/50-server.cnf or /etc/mysql/mysql.conf.d/mysqld.cnf
    [mysqld]
    # ... other settings ...
    max_allowed_packet = 64M
    # ... other settings ...
    

    Setting max_allowed_packet to an excessively high value (e.g., several gigabytes) can make your server vulnerable to Denial of Service (DoS) attacks, as it could consume too much memory when handling large, malicious packets. Choose a value that accommodates your legitimate application needs without being overly generous.

  4. Restart the MySQL/MariaDB service: After saving the changes, you must restart the database service for them to take effect.

    For MySQL 8.x:

    sudo systemctl restart mysql.service
    

    For MariaDB 10.x:

    sudo systemctl restart mariadb.service
    
  5. Verify the change: Connect to your database again and confirm the max_allowed_packet value:

    mysql -u root -p -e "SHOW VARIABLES LIKE 'max_allowed_packet';"
    

    The output should now reflect your new, larger value (e.g., 67108864 for 64MB).

2. Adjust PHP-FPM memory_limit (for PHP Applications)

If you're running a PHP application and dealing with large result sets, PHP's memory limit might be the bottleneck.

  1. Determine your PHP version and php.ini location: Check the PHP version used by your FPM pool. Common paths on Ubuntu 20.04 are /etc/php/X.X/fpm/php.ini for the FPM handler and /etc/php/X.X/cli/php.ini for command-line scripts.

    To find the current memory_limit and php.ini path for PHP-FPM, you can create a phpinfo.php file in your web root (/var/www/html/info.php):

    <?php phpinfo(); ?>
    

    Access http://your_domain/info.php in your browser and search for memory_limit and Loaded Configuration File.

    Alternatively, for the CLI, run:

    php -i | grep -E "Loaded Configuration File|memory_limit"
    
  2. Edit php.ini: Open the appropriate php.ini file for your PHP-FPM setup (e.g., /etc/php/8.1/fpm/php.ini):

    sudo nano /etc/php/8.1/fpm/php.ini
    

    Find the memory_limit directive and increase its value. A typical starting point for applications dealing with large data might be 256M or 512M.

    ; Maximum amount of memory a script may consume (128MB)
    ; http://php.net/memory-limit
    memory_limit = 256M
    
  3. Restart PHP-FPM service: After saving the changes, restart the PHP-FPM service to apply them.

    sudo systemctl restart php8.1-fpm.service
    

    (Replace php8.1-fpm.service with your actual PHP-FPM version, e.g., php7.4-fpm.service).

    While max_allowed_packet handles the size of data exchanged with the database, memory_limit ensures PHP has enough memory to process that data after it's received. Both can cause "MySQL server has gone away" if their limits are hit.

3. Review MySQL/MariaDB Server Timeouts (wait_timeout, interactive_timeout)

While not the primary cause of "packet too large," general "MySQL server has gone away" errors can be related to connection timeouts. If your large query takes a very long time, the connection might time out before the query completes.

  1. Check current timeout values:

    mysql -u root -p -e "SHOW VARIABLES LIKE 'wait_timeout';"
    mysql -u root -p -e "SHOW VARIABLES LIKE 'interactive_timeout';"
    

    These values are in seconds. wait_timeout applies to non-interactive connections (e.g., web applications), while interactive_timeout applies to interactive clients (e.g., mysql CLI).

  2. Adjust timeout values (if necessary): If your queries consistently run longer than these timeouts, you might consider increasing them. Edit the same MySQL/MariaDB configuration file as in Step 1 (e.g., /etc/mysql/mariadb.conf.d/50-server.cnf):

    [mysqld]
    # ...
    wait_timeout = 3600    # 1 hour (default is 28800 seconds or 8 hours)
    interactive_timeout = 3600 # 1 hour (default is 28800 seconds or 8 hours)
    
  3. Restart the MySQL/MariaDB service:

    sudo systemctl restart mysql.service # or mariadb.service
    

4. Client-side max_allowed_packet Configuration (Less Common for Web Apps)

In rare cases, your specific database client or ORM might have its own max_allowed_packet setting or require it to be set explicitly.

  • For the mysql command-line client: You can configure this in your user's ~/.my.cnf file or the global /etc/mysql/my.cnf under the [mysql] section:

    # ~/.my.cnf or /etc/mysql/my.cnf
    [mysql]
    max_allowed_packet = 64M
    

    This ensures that when you use the mysql client, it attempts to send/receive larger packets.

  • For application-specific drivers: Consult your application's documentation or the specific database driver you are using (e.g., a Python mysqlclient connector, a Node.js mysql package) to see if there's an option to set max_allowed_packet at the connection level. Most modern drivers will respect the server's max_allowed_packet by default, but it's worth checking if issues persist.

5. Optimize Application Queries & Data Handling

The most robust and long-term solution is to optimize your application's database interactions to avoid hitting these packet size limits in the first place.

  • Break down large INSERT statements: Instead of a single INSERT statement with thousands of rows, break it into smaller batches. This is more resilient to network issues and less likely to exceed packet limits.

    -- Instead of:
    INSERT INTO my_table (col1, col2) VALUES (...), (...), (...), ...;
    
    -- Do:
    INSERT INTO my_table (col1, col2) VALUES (...), (...);
    INSERT INTO my_table (col1, col2) VALUES (...), (...);
    -- ... repeat in batches
    
  • Use LOAD DATA INFILE for bulk imports: For importing very large files (e.g., CSV, TSV), LOAD DATA INFILE is significantly more efficient and handles large datasets better than multiple INSERT statements.

    LOAD DATA INFILE '/path/to/your/data.csv'
    INTO TABLE my_table
    FIELDS TERMINATED BY ','
    ENCLOSED BY '"'
    LINES TERMINATED BY 'n'
    IGNORE 1 ROWS;
    
  • Paginate large SELECT queries: When retrieving extensive result sets, implement pagination in your application to fetch data in smaller, manageable chunks. This reduces memory usage on both the server and client.

    SELECT * FROM my_table LIMIT 100 OFFSET 0;   -- First 100
    SELECT * FROM my_table LIMIT 100 OFFSET 100; -- Next 100
    

    While increasing max_allowed_packet and memory_limit can provide immediate relief, optimizing your application's data handling is crucial for scalability, performance, and long-term stability. Excessive reliance on large packet sizes can indicate an inefficient application design.