Part of the guide: MySQL Errors & Fixes for PHP and Laravel Developers

MySQL Server Has Gone Away (2006) in Laravel & XAMPP: Fix

By Published 20 min read MySQL
MySQL Server Has Gone Away (2006) in Laravel & XAMPP: Fix

Your Laravel application is running fine. You open a page, import some data, or execute a background job. Suddenly, the database connection fails.

The error looks like this:

SQLSTATE[HY000]: General error: 2006 MySQL server has gone away

Sometimes you see a related error:

SQLSTATE[HY000]: General error: 2013 Lost connection to MySQL server during query

If you have encountered either message, the first thing to understand is that your database has not necessarily crashed.

MySQL server has gone away (2006) means your application tried to communicate through a database connection that was no longer usable.

The server might have closed an idle connection. A large SQL statement might have exceeded the allowed packet size. The database service might have restarted while Laravel was still processing a request.

These situations produce similar errors, but they need different fixes.

Quick fix: Start by checking wait_timeout, max_allowed_packet, and the database server's uptime. If the problem happens after a long period of inactivity, investigate connection expiration. If it happens during a large import or INSERT statement, inspect the packet limit. If several requests fail together, read the database error log.

This guide walks through the diagnosis and fixes for Laravel, Windows XAMPP, MySQL, MariaDB, and cPanel hosting.

1. What Causes MySQL Server Has Gone Away (2006)?

The two common lost-connection errors come from the MySQL client library.

ErrorMySQL identifierWhat happened
2006CR_SERVER_GONE_ERRORThe client could not successfully send a query to the server
2013CR_SERVER_LOSTThe client did not receive a complete response from the server

The operating system and client library can affect which error appears.

Both errors can indicate that the connection was interrupted, but they do not identify the underlying cause by themselves.

Cause 1: The database connection timed out

MySQL uses wait_timeout to control how long an inactive, non-interactive connection can remain open.

A commonly documented default is:

wait_timeout = 28800

That is eight hours.

A hosting provider may configure a much shorter timeout.

Imagine an Artisan command that connects to MySQL, downloads attendance records from another server, processes the files, and then attempts another SQL query.

If the connection remains idle longer than the configured timeout, MySQL may close it.

The next query can return error 2006.

One detail matters here: wait_timeout is an idle-connection timeout. It does not limit how long an actively running SQL query may execute.

Cause 2: max_allowed_packet is too small

MySQL uses max_allowed_packet to limit communication packet sizes.

A single large SQL statement may exceed that setting.

For example:

INSERT INTO articles (title, body)
VALUES
('First article', 'Large HTML content'),
('Second article', 'Another large HTML document');

This simple example will not normally cause a problem.

But imagine inserting thousands of articles with substantial HTML content in one statement.

The resulting SQL request may exceed the permitted packet size.

When a packet is too large, the database can reject it and close the connection.

This is why a small import may work while a larger import consistently fails.

Cause 3: The database restarted

If MySQL stops or restarts, its existing connections are terminated.

Laravel might still have a reference to an old connection.

When it sends the next query, the connection is no longer usable.

Possible reasons for a restart include scheduled maintenance, a service crash, memory exhaustion, or an administrator restarting the database.

Do not assume a crash occurred without checking the server log.

Cause 4: The connection was killed

A database administrator can terminate a connection using the KILL statement.

Some hosting environments also terminate connections or queries when resource limits are exceeded.

The application may report the resulting interruption as a lost connection.

Cause 5: Network or communication problems

A remote database connection can fail even when the database service is healthy.

Possible causes include unstable networking, firewall resets, database proxy timeouts, or an interrupted transfer.

If Laravel and MySQL run on the same Windows XAMPP installation, remote-network problems are generally less likely.

If your Laravel application connects to a database hosted elsewhere, investigate networking as well.

2. Check the Database Settings Before Changing Anything

I would start with the current database settings rather than immediately increasing timeouts.

You can run these checks in phpMyAdmin or a MySQL command-line client.

Step 1: Identify your database version

Open phpMyAdmin, select the SQL tab, and execute:

SELECT VERSION() AS server_version;

This tells you which database server you are connected to.

The distinction matters because XAMPP commonly uses MariaDB rather than Oracle MySQL.

For example, the Windows XAMPP 8.2.12 release included MariaDB 10.4.32.

If your installation has been upgraded or replaced, the version may be different.

Step 2: Check the timeout and packet limits

Run:

SHOW VARIABLES LIKE 'wait_timeout';
SHOW VARIABLES LIKE 'interactive_timeout';
SHOW VARIABLES LIKE 'max_allowed_packet';

You can compare the current session and global settings with:

SELECT
    @@SESSION.wait_timeout AS session_wait_timeout,
    @@GLOBAL.wait_timeout AS global_wait_timeout,
    @@SESSION.max_allowed_packet AS session_packet_limit,
    @@GLOBAL.max_allowed_packet AS global_packet_limit;

This comparison is useful because existing sessions do not necessarily receive every global setting change immediately.

The variables mean:

VariablePurpose
wait_timeoutControls inactive non-interactive connections
interactive_timeoutControls the initial idle timeout for interactive clients
max_allowed_packetLimits communication packet size
net_read_timeoutControls how long the server waits for incoming data
net_write_timeoutControls how long the server waits while sending data

The packet value is reported in bytes.

For reference:

ValueSize
10485761 MiB
1677721616 MiB
6710886464 MiB

If you see 16777216, the packet limit is 16 MiB.

That does not automatically mean the value is too small. You need to compare it with the size of the failing statement.

Step 3: Check the database uptime

Run:

SHOW GLOBAL STATUS LIKE 'Uptime';

The result shows how many seconds the database server has been running.

Compare it with the time of the error.

A recent restart can help explain why previously established connections stopped working.

However, uptime alone does not tell you whether the database crashed.

The service could have restarted normally, or someone may have restarted it after the original error.

Use the error log to establish what happened.

Step 4: Find the database error log

Run:

SHOW VARIABLES LIKE 'log_error';

On a typical Windows XAMPP installation, the database logs are located under:

C:\xampp\mysql\data\

The exact filename depends on the configuration.

Check the entries recorded around the time of the failure.

Look for unexpected shutdowns, startup messages, oversized-packet errors, or resource problems.

If you are on shared hosting and cannot access the database log, ask your provider to inspect it.

Step 5: Match the symptom to the cause

What happensPossible causeWhat to try
Error after a long pauseIdle connection expiredReconnect before the next query
Error during a large INSERTPacket limit exceededReduce batch size or adjust packet limit
Error during SQL importOversized statement or connection failureInspect the failing statement
Error while reading many rowsTransfer, query, or network problemProcess results in smaller batches
Many pages fail togetherDatabase restart or outageCheck database status and error log
Error inside a transactionConnection was lost during the transactionReview transaction recovery
Error on a remote databaseNetwork or proxy interruptionCheck network stability and timeouts

Avoid applying several unrelated fixes at once.

If you change the packet limit, timeout values, and Laravel code together, it becomes harder to determine which change actually solved the problem.

3. Fix max_allowed_packet in Windows XAMPP

If a large SQL statement is causing the problem, the next step is to inspect XAMPP's packet limit.

The configuration file is commonly located at:

C:\xampp\mysql\bin\my.ini

Use the actual installation path if you installed XAMPP elsewhere.

Step 1: Back up my.ini

Before editing the file, create a backup.

Open Command Prompt and run:

copy "C:\xampp\mysql\bin\my.ini" "C:\xampp\mysql\bin\my.ini.bak"

This gives you a copy to restore if the database fails to start after the change.

Step 2: Stop the database service

Open the XAMPP Control Panel.

Find the MySQL row and click Stop.

Wait until the service has stopped.

The panel may say MySQL even when the installed database engine is MariaDB.

Step 3: Update the correct setting

Open the active my.ini file.

Find the [mysqld] section.

Look for an existing max_allowed_packet entry.

For example:

[mysqld]
max_allowed_packet=64M

If the setting already exists, change the existing value rather than adding a duplicate.

This example sets the packet limit to 64 MiB.

It is a reasonable test value when the current limit is insufficient, but it is not required for every Laravel application.

Avoid setting it to an extremely large number unless you know why the application needs it.

Step 4: Understand the client settings

The same file may contain sections such as:

[mysql]
max_allowed_packet=64M

[mysqldump]
max_allowed_packet=64M

These settings apply to the respective command-line programs.

They do not replace the server setting under [mysqld].

Also, adding a setting under [mysql] does not automatically change how phpMyAdmin or PHP's database driver handles every request.

Different database clients may use their own limits.

Step 5: Start MySQL again

Save the configuration file.

Return to the XAMPP Control Panel and start MySQL.

If the database refuses to start, restore your previous configuration and read the error log.

Do not delete database files to fix a configuration error.

For more detailed recovery steps, see MySQL Shutdown Unexpectedly in XAMPP.

Step 6: Verify that the setting changed

Open a new database connection and run:

SHOW GLOBAL VARIABLES LIKE 'max_allowed_packet';

For the example configuration, the expected value is:

67108864

If the value is unchanged, confirm that you edited the configuration file used by the running database service.

Can you change the packet limit without restarting?

On supported MySQL and MariaDB versions, an administrator with sufficient privileges can run:

SET GLOBAL max_allowed_packet = 67108864;

This changes the global value at runtime.

Existing connections may retain their previous session value.

The change is also not necessarily persistent across service restarts.

For a lasting change, update the appropriate server configuration.

Remember that increasing max_allowed_packet only helps when packet size is actually the problem.

It will not repair an expired connection, an unstable network, or a crashing database server.

4. Fix Large SQL Imports in phpMyAdmin and Command Prompt

Large database imports are one of the most common situations where developers encounter error 2006.

But the total SQL file size is not the same as the size of an individual database packet.

A large dump containing thousands of small INSERT statements can import without exceeding the packet limit.

A smaller dump containing one enormous INSERT statement may fail.

Check PHP upload limits first

When you import through phpMyAdmin, PHP and the database server both have limits.

SettingWhat it affects
upload_max_filesizeLargest uploaded file accepted by PHP
post_max_sizeMaximum HTTP POST request size
max_execution_timePHP execution-time limit
memory_limitMemory available to the PHP script
max_allowed_packetDatabase communication packet size

If the SQL file cannot be uploaded at all, check the PHP limits first.

If the upload succeeds but the import fails during execution, look at the SQL statements, packet settings, error logs, and execution environment.

Import a SQL file using Command Prompt

For a large SQL dump, the command-line client avoids phpMyAdmin's PHP upload limits.

Open Windows Command Prompt.

Run:

cd /d C:\xampp\mysql\bin

mysql.exe -u root -p --max_allowed_packet=64M my_database < "C:\path\to\dump.sql"

Replace my_database with your actual database name.

Replace the file path with the location of your SQL dump.

The command does the following:

  1. Opens the XAMPP MySQL binary directory.
  2. Starts the MySQL command-line client.
  3. Connects using the specified database account.
  4. Sets the client's packet limit for this operation.
  5. Imports the SQL statements from the file.

The destination database should already exist unless the dump includes statements that create it.

If your local XAMPP root account has no password, pressing Enter at the password prompt may be sufficient.

Never assume that a live database has an empty password.

Run this example in Command Prompt. Standard PowerShell input redirection does not use the same < syntax.

Before importing: Review the SQL dump and confirm the destination database. A dump may contain statements that delete or replace existing data.

Reduce the size of individual INSERT statements

If you control the source database, you can produce a dump without extended INSERT statements.

For example:

cd /d C:\xampp\mysql\bin

mysqldump.exe -u root -p --skip-extended-insert my_database > "C:\path\to\dump.sql"

The --skip-extended-insert option tells mysqldump to avoid combining many rows into one INSERT statement.

The resulting dump may be larger and slower to restore.

However, each statement will typically be smaller.

This can help when multi-row INSERT statements exceed the server's packet limit.

It will not solve a problem caused by one individual row containing a very large binary or text value.

5. Fix Laravel Connections, Queue Workers, and Big Inserts

Laravel already handles some database connection failures.

That does not mean you can ignore them.

The framework can recognize certain lost-connection exceptions and attempt to reconnect, but the behavior depends on the query context.

How Laravel handles a lost connection

Laravel 12 uses lost-connection detection inside its database connection implementation.

If a query fails with a recognized lost-connection error and no transaction is active, Laravel can attempt to reconnect and retry the query.

That may recover from an expired idle connection.

It does not guarantee recovery from every failure.

If the database server is unavailable, reconnecting may fail.

If the SQL statement exceeds max_allowed_packet, executing the same oversized statement again will not help.

There is also a risk with failed write operations.

Suppose the server completes an INSERT but the network connection drops before Laravel receives the response.

The application may not know whether the write succeeded.

Blindly retrying that operation can insert duplicate records.

For important writes, use unique constraints or an idempotent operation design.

Reconnect after a long external operation

Suppose an Artisan command downloads attendance data from a biometric device.

The download takes several minutes, and the database connection remains unused during that time.

Once the data is ready, you can reconnect before saving it.

For example, inside an existing command or service:

use Illuminate\Support\Facades\DB;

// This operation may take several minutes.
$rows = $this->fetchAttendanceFromDevice($branch);

// Refresh the database connection.
DB::reconnect();

if (! empty($rows)) {
    DB::table('attendance_logs')->insert($rows);
}

This example assumes $branch and fetchAttendanceFromDevice() are defined in your application.

DB::reconnect() refreshes the default database connection.

If you need a named connection, use:

DB::reconnect('mysql');

Do not reconnect in the middle of an open transaction.

A new connection cannot continue the transaction that belonged to the previous connection.

Why Laravel transactions need special care

Consider this example:

use Illuminate\Support\Facades\DB;

DB::transaction(function () {
    DB::table('orders')
        ->where('id', 1001)
        ->update(['status' => 'processed']);

    DB::table('order_logs')->insert([
        'order_id' => 1001,
        'message' => 'Order processed',
    ]);
});

If the connection disappears while the transaction is running, Laravel cannot safely resume the original transaction on a new database connection.

That is why its ordinary lost-connection query retry behavior does not apply in the same way to queries inside active transactions.

For a connection lost close to the COMMIT operation, the application may not know whether the transaction was committed.

That matters for payments, invoices, orders, and other actions that must not be duplicated.

Keep transactions reasonably short and design retries around data consistency rather than simply repeating the entire operation.

Restart Laravel queue workers properly

Laravel queue workers can remain active for long periods.

Because the worker process is reused between jobs, it may retain database connections and application state.

Laravel includes logic to stop a worker after certain unhandled lost-connection failures.

However, the worker needs a process supervisor or another mechanism to restart it.

A typical worker command is:

php artisan queue:work --sleep=3 --max-time=3600 --max-jobs=500

The options mean:

OptionPurpose
--sleep=3Sleep briefly when no job is available
--max-time=3600Limit the worker's overall running time
--max-jobs=500Exit after processing the configured number of jobs

These settings can help recycle long-running workers.

They are not a complete fix for database outages.

Also, --max-time does not forcibly terminate every running job the moment the duration is reached. The worker normally checks its exit conditions between processing jobs.

For Linux production servers, Laravel documents using Supervisor to manage queue workers.

On Windows, use a properly configured Windows-compatible process supervisor or service manager.

After a deployment, run:

php artisan queue:restart

This requests a graceful worker restart.

The restart command relies on Laravel's configured cache infrastructure to communicate the restart signal.

Use short-lived workers on shared hosting

If your cPanel hosting provider permits cron jobs but not permanent background processes, a short-lived queue worker may be more practical.

For example:

php artisan queue:work --stop-when-empty

The worker processes available jobs and exits when the queue becomes empty.

You can schedule it using cron if your hosting environment supports that approach.

Use the correct PHP executable and project path.

Also, avoid overlapping cron executions unless your queue processing is designed to handle concurrent workers.

For a busy application with time-sensitive jobs, a continuously supervised worker is usually a better fit.

Split large Laravel INSERT statements

If an import contains thousands of rows, avoid building one enormous INSERT statement.

For example:

use Illuminate\Support\Facades\DB;

foreach (array_chunk($rows, 200) as $chunk) {
    DB::table('attendance_logs')->insert($chunk);
}

This code divides the input array into batches of 200 rows.

The number is only a starting point.

A batch containing large text values may need to be smaller.

A batch containing short values may safely contain more rows.

The right size depends on your data and database limits.

Also, array_chunk() does not solve PHP memory problems if $rows already contains millions of records.

For very large imports, read records incrementally instead of loading everything into memory.

Read large tables in smaller batches

Avoid loading an entire large table when you only need to process records one at a time.

Instead of:

$employees = DB::table('employees')->get();

use:

DB::table('employees')
    ->chunkById(500, function ($employees) {
        foreach ($employees as $employee) {
            // Process this employee.
        }
    });

This retrieves records in smaller groups using the table's ID column.

For sequential processing, lazyById() is another option.

These approaches reduce memory usage and avoid transferring a very large result set in one request.

They do not eliminate problems caused by a database crash or an unstable network.

6. Common Problems and Troubleshooting Mistakes

If the error continues after checking the main settings, use the actual failure pattern to narrow the investigation.

Problem: MySQL server has gone away after an idle period

Check:

SHOW VARIABLES LIKE 'wait_timeout';

If the application leaves connections unused for long periods, reconnect before the next database operation.

Do not automatically set wait_timeout to an extremely high value.

Long idle timeouts can leave unused connections occupying server resources.

Problem: Lost connection during a large SELECT

A large query result can place pressure on the database, PHP memory, or the network connection.

First, check whether the query can return fewer rows.

Use pagination or incremental processing where appropriate.

If the problem occurs during result transfer, investigate net_write_timeout, client-side read timeouts, and network stability.

Be careful with net_read_timeout. It controls how long the server waits for incoming data from the client, not the entire duration of a SQL query.

Increasing it is not a universal fix for error 2013.

Problem: Database keeps restarting

Check:

SHOW GLOBAL STATUS LIKE 'Uptime';

Then inspect the error log:

SHOW VARIABLES LIKE 'log_error';

Look for evidence of a crash, startup error, or resource problem.

Do not delete InnoDB files or overwrite the database data directory.

If MySQL will not start, investigate the startup error separately.

Problem: Shared hosting does not allow configuration changes

On ordinary cPanel shared hosting, you generally cannot edit the server's MySQL configuration file.

You may also lack permission to run:

SET GLOBAL max_allowed_packet = 67108864;

That is normal for a restricted hosting account.

You can still reduce INSERT batch sizes, avoid large SQL statements, reconnect in long-running commands, and ask your provider to inspect the database logs.

When requesting support, include the exact error, affected query or operation, timestamp, and current database settings.

Do not send database passwords or your complete Laravel .env file.

Problem: Error returns after restarting MySQL

Restarting the database clears existing connections.

That can temporarily make the application work again.

But if the underlying issue is an oversized statement or an idle worker, the same error can return.

Use the original failing operation as your test.

If the error reappears under the same conditions, focus on that repeatable pattern.

Problem: Too many database connections

Increasing idle timeouts or enabling persistent connections without planning connection capacity can create another problem.

On shared hosting, you may encounter:

User has exceeded the max_user_connections resource

If that happens, review how many database connections the application opens and how they are released.

The MySQL max_user_connections Error on Shared Hosting guide covers that problem separately.

Problem: SQL imports create duplicate records

After a failed import, do not assume that every statement was rolled back.

Some statements may already have completed.

Restarting an import without checking the existing data can create duplicates or overwrite records.

Use a backup, review the dump, and confirm the destination database before retrying.

For application-managed imports, consider unique constraints and a resumable import process.

Quick verification after fixing the error

Once you have made the relevant change, check these results:

  1. The database server remains running.
  2. The expected max_allowed_packet and timeout values are active.
  3. The original failing operation completes.
  4. Laravel logs contain no new matching lost-connection error for that test.
  5. Imported records are complete.
  6. No duplicate records were created.
  7. Queue jobs complete successfully.
  8. The database error log does not show another unexpected restart.

Do not rely on a successful homepage load as proof that the database problem is resolved.

If the error originally happened during a large import, repeat that import safely in a test environment.

If it happened during a long-running job, verify the job under the same conditions.

For applications that regularly need queue workers, large imports, or server-level database tuning, see Shared Hosting vs VPS for Laravel.

7. FAQ

What does MySQL server has gone away error 2006 mean?

Error 2006 means the database client could no longer communicate through its existing connection.

It can happen because the connection timed out, the database restarted, a communication packet exceeded the allowed limit, or another connection problem occurred.

Check wait_timeout, max_allowed_packet, server uptime, and the database error log to identify the cause.

What should max_allowed_packet be in XAMPP?

There is no single correct setting for every application.

If your current packet limit is too small for a legitimate SQL statement, 64M can be a reasonable troubleshooting value.

On a typical Windows XAMPP installation, configure it under [mysqld] in the active my.ini file.

Restart the database and verify the value using:

SHOW GLOBAL VARIABLES LIKE 'max_allowed_packet';

If the original error was caused by a timeout rather than an oversized packet, increasing this setting will not help.

Does Laravel reconnect automatically after MySQL server has gone away?

Laravel 12 can detect some lost connections and attempt to reconnect and retry a query when no transaction is active.

It cannot guarantee recovery from every disconnection.

Inside an active transaction, Laravel cannot simply reconnect and continue the original transaction.

Long-running jobs should handle connection failures carefully, and write operations should be designed to prevent duplicate records during retries.

Why does a large SQL import fail in phpMyAdmin?

A large SQL import can fail because of PHP upload limits, execution limits, oversized SQL statements, packet limits, or database connection problems.

If the file cannot upload, check upload_max_filesize and post_max_size.

If the upload succeeds but database execution fails, inspect the failing SQL statement and max_allowed_packet.

Using the MySQL command-line client can avoid PHP upload limits, but the server's database packet limit still applies.

Final check

When MySQL reports that the server has gone away, do not start by increasing every timeout or restarting services repeatedly.

Find out whether the connection expired, the request was too large, or the database service actually stopped.

Then make the smallest change that addresses that cause and repeat the original failing operation.

That approach is more reliable than a configuration change that only hides the problem until it happens again.

Sources

  • MySQL 8.4: MySQL Server Has Gone Away

https://dev.mysql.com/doc/refman/8.4/en/gone-away.html

  • MySQL 8.4: Packet Too Large

https://dev.mysql.com/doc/refman/8.4/en/packet-too-large.html

  • MySQL 8.4: Server System Variables

https://dev.mysql.com/doc/refman/8.4/en/server-system-variables.html

  • MySQL 8.4: mysqldump

https://dev.mysql.com/doc/refman/8.4/en/mysqldump.html

  • MariaDB: Server System Variables

https://mariadb.com/docs/server/server-management/variables-and-modes/server-system-variables

  • Laravel 12: Queue Documentation

https://laravel.com/docs/12.x/queues

  • Laravel 12: Database Connection Source

https://github.com/laravel/framework/blob/12.x/src/Illuminate/Database/Connection.php

  • Laravel 12: Queue Worker Source

https://github.com/laravel/framework/blob/12.x/src/Illuminate/Queue/Worker.php

  • Apache Friends: XAMPP 8.2.12 Release

https://www.apachefriends.org/blog/new_xampp_20231119.html

Free tools for MySQL work

All free tools →

More MySQL articles