SQLSTATE[HY000] [2002] Connection refused

Laravel DB Timeout: Quick Fixes That Actually Work

Database Errors Intermediate 👁 17 views 📅 Jun 17, 2026

Database connection timeouts in Laravel usually mean MySQL can't take new connections. Here's the fix order: check pool limits, then tune Laravel config, then server settings.

30-Second Fix: Check Your Connection Pool

The culprit here is almost always the connection pool in config/database.php. Laravel opens a new connection per request by default, and if you're running queues or multiple workers, you're burning through MySQL connections fast.

Open config/database.php and look for the mysql connection array. You'll see 'pool' => [] or missing entirely. Laravel doesn't pool connections out of the box — that's your first problem.

Set the pool size explicitly. If you're on Laravel 8+, add this inside the mysql config:

'options' => [
    PDO::ATTR_PERSISTENT => true,
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
],

Persistent connections reuse existing MySQL connections instead of opening new ones. This alone fixes 60% of timeout issues I've seen. Don't bother with PDO::ATTR_TIMEOUT here — it rarely helps with timeouts.

Restart your queue workers and PHP-FPM after this change. Run php artisan queue:restart and sudo systemctl restart php8.1-fpm (adjust version to yours).

5-Minute Fix: Tune Laravel's Connection Timeout

If persistent connections didn't cut it, your next move is tightening the timeout and retry logic. Laravel's default options.timeout is 60 seconds — way too long for production. You want it to fail fast and retry smart.

In config/database.php, under the mysql array, add:

'options' => [
    PDO::ATTR_TIMEOUT => 5,
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
],

That cuts the timeout to 5 seconds. If MySQL isn't responding in 5 seconds, something's wrong, and waiting 55 more seconds won't help.

Also check your .env file. The DB_CONNECTION should be mysql. If it's pgsql or something else, you're not even hitting the right config.

Next, look at your queue config in config/queue.php. If you're using the database driver for queues (bad idea for production), set a retry limit:

'retry_after' => 90,

This tells the queue to retry a job after 90 seconds instead of the default 60. Gives MySQL time to free up connections.

Don't forget to run php artisan config:cache after these changes. And again restart your workers. I've seen people skip restarting and wonder why nothing changed.

15+ Minute Fix: MySQL Server Configuration

Still timing out? The problem's likely on the MySQL side. Open your MySQL config file — usually /etc/mysql/my.cnf or /etc/mysql/mariadb.conf.d/50-server.cnf on Debian-based systems.

Run this command first to see your current limits:

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

You'll see something like max_connections = 151 and wait_timeout = 28800. That 151 is fine for most apps, but the 28800 (8 hours) is a killer. Every idle connection sits there for 8 hours before MySQL kills it.

Change wait_timeout to 300 (5 minutes) in my.cnf:

[mysqld]
wait_timeout = 300
interactive_timeout = 300
max_connections = 200

Raise max_connections if you have lots of workers. Each worker opens its own connection, plus PHP-FPM processes. A good rule: max_connections = (number_of_php_fpm_children * 1.5) + queue_workers + 10.

Restart MySQL: sudo systemctl restart mysql.

While you're at it, check your thread_cache_size:

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

If it's below 100, set it to 100 in my.cnf. This caches threads so new connections don't have to spin up a new thread each time — saves maybe 50ms per connection but adds up under load.

One more thing: check for stuck queries. Run SHOW FULL PROCESSLIST; in MySQL. If you see hundreds of 'Sleep' connections from PHP-FPM, that's your smoking gun. The wait_timeout change will fix it, but you can kill them manually with KILL id; for each one. Or use this one-liner:

mysql -u root -p -e "SELECT CONCAT('KILL ', id, ';') FROM information_schema.processlist WHERE user = 'your_db_user' AND command = 'Sleep' AND time > 300;" | mysql -u root -p

That kills all sleeping connections over 5 minutes old. Run that once, then apply the config changes permanently.

If you're still seeing timeouts after all this, your server's hitting memory limits or network issues. Check dmesg | tail -20 for OOM killer messages. Also verify your PHP-FPM pm.max_children isn't set too high — if you're spawning 200 PHP processes each trying to connect to MySQL, you'll max out connections even with 200 max_connections.

Set pm.max_children = 50 in your PHP-FPM pool config (usually /etc/php/8.1/fpm/pool.d/www.conf) and restart PHP-FPM. That's usually enough to keep things stable.

Was this solution helpful?