Laravel Queue Crash on cPanel VPS: Why MySQL Connections Drop and How to Fix It Fast
You’re watching your queue workers explode, the MySQL error log screams “Too many connections”, and the whole Laravel app grinds to a halt. It feels like every time you spin up a new job, the VPS takes a deep breath and chokes. If you’ve ever stared at a blinking cursor wondering whether to rewrite the whole architecture, this guide is for you. We’ll dig into the root cause, patch the crash, and give you a hardened VPS that can handle 10k+ jobs a day without shedding connections.
Why This Matters
Queue workers are the heartbeat of any modern Laravel‑powered SaaS. They power email campaigns, webhook dispatches, image processing, and more. When MySQL connections start dropping, you lose:
- Real‑time notifications
- Customer‑facing API reliability
- Revenue‑critical background billing jobs
In production environments—especially on a cPanel VPS shared with WordPress—those lost jobs become lost money.
Common Causes
- Unlimited queue workers: Supervisor spawns more processes than MySQL can handle.
- Default PHP‑FPM pool settings: Each FPM child opens a DB connection that never closes.
- cPanel’s MySQL limits: Shared hosting caps connections at 150 by default.
- Missing Redis cache: Jobs hit the DB for every lock check.
- Improper .env values: DB_MAX_CONNECTIONS not synced with MySQL server.
Step‑By‑Step Fix Tutorial
1. Audit Your Current Connection Count
# Check active connections
mysql -u root -p -e "SHOW STATUS LIKE 'Threads_connected';"
# Show max allowed connections
mysql -u root -p -e "SHOW VARIABLES LIKE 'max_connections';"
2. Tune MySQL for Higher Concurrency
Tip: Increase max_connections only if your VPS has enough RAM. A good rule of thumb is 1 MB per connection.
# Edit /etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
max_connections = 500
innodb_buffer_pool_size = 2G # Adjust to 70% of RAM
After editing, restart MySQL:
systemctl restart mysql
3. Limit Laravel Queue Workers
Keep workers around 2 × CPU cores and enforce a --timeout of 60 seconds.
# /etc/supervisor/conf.d/laravel-queue.conf
[program:laravel-queue]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan queue:work redis --sleep=3 --tries=3 --timeout=60
autostart=true
autorestart=true
numprocs=4 ; 2 × 2‑core VPS
user=www-data
redirect_stderr=true
stdout_logfile=/var/log/laravel/queue.log
Reload Supervisor:
supervisorctl reread && supervisorctl update
4. Enable Persistent Connections in Laravel
// config/database.php
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'strict' => true,
'options' => extension_loaded('pdo_mysql') ? [
PDO::ATTR_PERSISTENT => true,
] : [],
],
5. Add Redis for Queue Locking and Caching
# Install Redis (Ubuntu)
apt-get update && apt-get install -y redis-server
# Enable Redis in Laravel
// .env
CACHE_DRIVER=redis
QUEUE_CONNECTION=redis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
6. Adjust PHP‑FPM Pool Settings
Reduce pm.max_children to avoid spawning more DB connections than MySQL allows.
# /etc/php/8.2/fpm/pool.d/www.conf
pm = dynamic
pm.max_children = 50 ; depends on RAM
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
Restart PHP‑FPM:
systemctl restart php8.2-fpm
VPS or Shared Hosting Optimization Tips
- Swap Management: Disable swap on production VPS to force proper memory usage.
- cPanel MySQL Limits: Increase
max_user_connectionsvia WHM → “SQL Services → MySQL/MariaDB Configuration”. - Apache vs Nginx: Nginx + PHP‑FPM yields lower memory foot‑print. If you must stay on Apache, enable
mod_proxy_fcgiandWorker MPM. - Composer Autoloader Optimisation: Run
composer install --optimize-autoloader --no-devduring deployment. - Cloudflare Caching: Off‑load static assets; set
Cache‑Level: Aggressiveto reduce DB hits.
Real World Production Example
Acme SaaS runs a 8‑core Ubuntu 22.04 VPS with 32 GB RAM, Nginx, PHP‑FPM 8.2, and Redis. Before the fix they hit max_connections = 151, losing 12 % of queued emails during peak traffic.
After applying the steps:
- MySQL
max_connectionsraised to 500. - Supervisor limited workers to 8 processes.
- Redis reduced DB lock queries by 87 %.
- PHP‑FPM pool set to 80 children, keeping RAM usage stable.
Result: 0 MySQL connection errors for a month, email deliverability up 15 %, and CPU average dropped from 78 % to 42 %.
Before vs After Results
| Metric | Before | After |
|---|---|---|
| MySQL Connections (peak) | 160 (exceeded) | 312 (within limit) |
| Queue Workers | 12 (over‑provisioned) | 8 (optimal) |
| CPU Avg. | 78 % | 42 % |
| Job Failure Rate | 12 % | 0 % |
Security Considerations
When you raise max_connections and enable persistent connections, you also widen the attack surface. Follow these safeguards:
- Use strong MySQL passwords and rotate them quarterly.
- Restrict remote MySQL access to
127.0.0.1viabind-address. - Enable
mysql_secure_installationto remove anonymous users. - Limit Supervisor commands to the
www-datauser. - Apply
fail2banrules for repeated failed DB logins.
Bonus Performance Tips
Success: Enable Laravel Horizon for real‑time queue metrics and auto‑scaling.
# Install Horizon
composer require laravel/horizon
# Publish config
php artisan horizon:install
# Start Horizon with Supervisor
[program:horizon]
process_name=%(program_name)s
command=php /var/www/html/artisan horizon
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/log/laravel/horizon.log
Additional ideas:
- Use
php artisan optimizeafter each deploy. - Cache config and routes:
php artisan config:cache && php artisan route:cache. - Leverage Cloudflare “Rate Limiting” to protect API endpoints that feed the queue.
- Consider Dockerizing the stack; isolate MySQL, Redis, and PHP‑FPM containers with resource limits.
FAQ
Q: My VPS is on cPanel and I can’t edit
mysqld.cnf. What now?A: Use WHM → “SQL Services → MySQL/MariaDB Configuration” to raise
max_connections. Then restart MySQL via WHM.
Q: Should I switch from MySQL to MariaDB?
A: MariaDB is a drop‑in replacement and often handles connection spikes better. Test on a staging VPS before production.
Q: How many Redis instances do I need?
A: One instance per server is fine for most apps. Use separate databases (0‑15) for cache vs queues to avoid key collisions.
Final Thoughts
Queue crashes on a cPanel VPS are rarely a “Laravel bug” – they’re a signal that the underlying infrastructure is out of sync with the workload. By aligning MySQL limits, trimming worker counts, and adding Redis for lock handling, you regain control and turn a flaky queue into a reliable background engine.
Take the time to document each change, monitor SHOW GLOBAL STATUS LIKE 'Threads_connected' after deployments, and you’ll spot regressions before they affect customers.
Looking for an ultra‑fast, managed VPS that already ships with Redis, PHP‑FPM, and MySQL tuned for Laravel? Cheap secure hosting on Hostinger can get you up and running in minutes.
No comments:
Post a Comment