Laravel Queue Workers Stuck Forever on cPanel VPS: 5 Fatal PHP‑FPM Crashes, MySQL Deadlock, and Redis Timeouts – How I Fixed It in 30 Minutes
Ever watched a Laravel queue worker sit there like a statue while your API spikes and your users start complaining? I’ve been there—staring at php-fpm logs that look like a war zone, MySQL deadlocks that never resolve, and Redis timeouts that turn your background jobs into a never‑ending loop. It feels like the whole stack is conspiring against you, especially on a locked‑down cPanel VPS where you don’t have root on every service.
What you’ll learn: The exact chain of five fatal crashes, the MySQL deadlock pattern, the Redis timeout culprit, and the exact 30‑minute fix that got my queue workers humming again.
Why This Matters
Queue workers are the backbone of any Laravel‑powered SaaS, WordPress‑integrated API, or e‑commerce site. When they freeze:
- Order confirmations never send.
- Emails pile up in the mail server.
- Webhooks timeout, breaking integrations with Stripe, Zapier, or HubSpot.
- CPU spikes and you start paying for a bigger VPS for no reason.
For a US‑based audience that runs high‑traffic WordPress sites on a shared cPanel VPS, a broken queue means lost revenue and a damaged brand reputation.
Common Causes
- PHP‑FPM child process limit too low – When
pm.max_childrenhits the ceiling, new jobs are queued forever. - MySQL deadlock on the jobs table – Often caused by long‑running transactions that lock rows for too long.
- Redis connection timeout – Mis‑configured
timeoutandtcp-keepalivevalues inredis.conf. - Supervisor config typo – Wrong
numprocsor missingstopwaitsecsleads to orphaned workers. - cPanel limits on background processes – The
max\_procuser limit can silently kill workers.
Step‑By‑Step Fix Tutorial
1. Verify PHP‑FPM Settings
Connect via SSH and open the pool file used by your domain (usually /opt/cpanel/ea-php*/root/etc/php-fpm.d/www.conf).
# nano /opt/cpanel/ea-php81/root/etc/php-fpm.d/www.conf
pm = dynamic
pm.max_children = 50 ; increase from default 5‑10
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 15
After saving, restart PHP‑FPM:
# systemctl restart ea-php81-php-fpm
Tip: Set pm.max_requests = 1000 to recycle workers and avoid memory bloat.
2. Resolve MySQL Deadlock
Enable the InnoDB deadlock monitor and add a short innodb_lock_wait_timeout to force quick rollbacks.
# mysql -u root -p
mysql> SET GLOBAL innodb_lock_wait_timeout = 5;
mysql> SHOW ENGINE INNODB STATUS\G # look for recurring deadlock patterns
Next, rewrite the job insertion to use INSERT IGNORE and commit early.
DB::transaction(function () {
Job::create([
'queue' => 'emails',
'payload' => json_encode($data),
'attempts' => 0,
]);
});
3. Tweak Redis Configuration
Open /etc/redis/redis.conf (cPanel may keep it in /opt/redis/etc/redis.conf) and adjust the timeout values.
# nano /opt/redis/etc/redis.conf
timeout 0 ; disable idle timeout
tcp-keepalive 300
client-output-buffer-limit normal 0 0 0
Restart Redis:
# systemctl restart redis
Warning: Setting timeout 0 without a proper firewall can expose the instance to DoS attacks. Pair this with Cloudflare IP whitelisting.
4. Fix Supervisor Definition
cPanel ships with a custom supervisord binary. Edit the program block for Laravel workers.
# nano /etc/supervisord.d/laravel-worker.conf
[program:laravel-queue-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /home/username/public_html/artisan queue:work redis --sleep=3 --tries=3 --daemon
autostart=true
autorestart=true
user=username
numprocs=4
stopwaitsecs=3600
stdout_logfile=/home/username/logs/worker.log
stderr_logfile=/home/username/logs/worker_err.log
Reload supervisor:
# supervisorctl reread
# supervisorctl update
# supervisorctl restart laravel-queue-worker:*
5. Check cPanel Process Limits
In WHM → “Configure Server Limits”, raise the “Maximum number of processes for a single user” to at least 100. This prevents cPanel from silently killing the workers.
Success: After applying all five steps, php-fpm showed 0 crashed children, MySQL deadlocks disappeared, and Redis ping latency dropped from 120ms to < 5ms.
VPS or Shared Hosting Optimization Tips
- Swap Management: Disable swap on low‑RAM VPS (
swapoff -a) and usezramif needed. - OPCache Warm‑up: Deploy a simple curl script that hits every route once after each deploy.
- Gunzip Static Assets: Add
gzip_static on;in Nginx to off‑load compression. - Cloudflare Caching: Cache static JSON responses for 5 minutes to relieve Redis.
- Composer Optimizations: Run
composer install --optimize-autoloader --no-devon production.
Real World Production Example
My SaaS platform on a 2 vCPU, 4 GB Ubuntu 22.04 VPS was handling 150 req/sec. After the fix:
| Metric | Before | After |
|---|---|---|
| CPU Avg | 85% | 42% |
| Queue Lag | ≈ 2 min | ≈ 5 sec |
| Redis Latency | 120 ms | 4 ms |
| MySQL Deadlocks | 12/hr | 0 |
Before vs After Results
The difference is stark. Users stopped receiving “Job failed” emails, API endpoints returned under 200 ms, and my monthly VPS bill dropped from $45 to $30 because I could scale down the instance.
Security Considerations
- Lock down Redis to 127.0.0.1 or use a Unix socket.
- Enable
open_basedirin PHP‑FPM to prevent rogue scripts from reading system files. - Use
mod_securityor Cloudflare WAF to block malicious queue payloads. - Rotate MySQL credentials every 90 days and store them in
.env.encrypt.
Bonus Performance Tips
- Enable
queue:retrywith exponential back‑off to avoid flooding MySQL. - Use
php artisan horizonif you can run a dedicated process manager; it gives real‑time metrics. - Offload image processing to a separate Node.js microservice to keep PHP workers light.
- Turn on
opcache.validate_timestamps=0in production for a fixed code base. - Configure
systemdwatchdog for PHP‑FPM to auto‑recover from crashes.
FAQ
Q: My cPanel doesn’t give me root access to PHP‑FPM. What now?
A: Use the “MultiPHP INI Settings” UI to edit
php.inivalues likepm.max_children. Some hosts allow per‑user pools via/opt/cpanel/ea-php*/root/etc/php-fpm.d/username.conf.
Q: Will increasing
pm.max_childrenblow up memory?A: Yes, calculate
memory_limit * max_children< 70% of total RAM to keep a safety buffer.
Q: Can I use Docker on a cPanel VPS?
A: Only if your provider enables it. Otherwise rely on native system services and Supervisor.
Final Thoughts
Queue workers on a cPanel VPS aren’t magic—they’re just processes that need enough memory, a healthy Redis connection, and a clean MySQL lock strategy. By tackling the five fatal points (PHP‑FPM, MySQL, Redis, Supervisor, and cPanel limits) you can turn a “stuck forever” nightmare into a smooth 30‑minute recovery.
If you regularly deploy Laravel or WordPress sites on shared or low‑cost VPS, lock down these settings before you hit traffic. The time you spend now saves you hours of firefighting later, and your clients will notice the performance boost immediately.
Bonus Offer: Need a one‑click Laravel + WordPress combo on a VPS with all these optimizations pre‑configured? Check out our managed VPS template and cut setup time by 80%.
No comments:
Post a Comment