Laravel Queue Workers Crashing on cPanel VPS – Fast Fix for MySQL Timeouts, File Permissions, and PHP‑FPM Overloads that Stop Your Deployment 24/7
It’s 2 a.m. and your Laravel queue is dead. The php artisan queue:work process keeps restarting, the logs are flooded with “MySQL server has gone away”, and every API request hits a 502. Sound familiar? You’re not alone—many developers hitting a cPanel‑managed VPS hit the same wall when PHP‑FPM, MySQL, and file permissions clash.
Why This Matters
Queue workers are the backbone of any modern SaaS or WordPress‑integrated Laravel app. They handle email, notifications, image processing, and background API syncs. When they crash:
- Customer experience drops instantly.
- Revenue‑critical jobs (billing, webhooks) stop.
- Server resources spin out of control, raising your cloud bill.
- Deployments become a nightmare, and you lose precious development time.
Fixing the root cause not only restores uptime but also unlocks the performance headroom needed for scaling.
Common Causes
1. MySQL connection timeout & max‑allowed‑packet
If a job runs longer than wait_timeout or tries to push a huge payload, MySQL drops the connection and the worker dies.
2. File permission mismatches on storage/ and bootstrap/cache/
cPanel sometimes runs PHP under the nobody user, while you deploy as youruser. Mis‑aligned permissions cause “Permission denied” errors that silently kill workers.
3. PHP‑FPM process limits
Default pm.max_children values (often 5‑10) are too low for a busy queue. When the limit is hit, new jobs are queued in the OS and eventually time out.
4. Supervisor misconfiguration
Supervisor may restart workers on every tiny error, leading to a rapid crash‑restart loop.
Step‑By‑Step Fix Tutorial
Step 1 – Tune MySQL
Open your my.cnf (usually /etc/mysql/my.cnf) and apply the following overrides:
[mysqld]
max_allowed_packet = 64M
wait_timeout = 300
interactive_timeout = 300
innodb_flush_log_at_trx_commit = 2
Restart MySQL:
sudo systemctl restart mysql
Step 2 – Fix Storage Permissions
# Replace "youruser" with the cPanel account name
sudo chown -R youruser:youruser /home/youruser/public_html/storage
sudo chown -R youruser:youruser /home/youruser/public_html/bootstrap/cache
# Set correct directory permissions
find /home/youruser/public_html/storage -type d -exec chmod 775 {} \;
find /home/youruser/public_html/bootstrap/cache -type d -exec chmod 775 {} \;
find /home/youruser/public_html/storage -type f -exec chmod 664 {} \;
SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1 to your .htaccess if you use API token auth, otherwise Laravel may reject jobs silently.Step 3 – Boost PHP‑FPM Settings
Edit the pool file used by cPanel (usually /opt/cpanel/ea-php*/root/etc/php-fpm.d/www.conf).
pm = dynamic
pm.max_children = 30
pm.start_servers = 6
pm.min_spare_servers = 4
pm.max_spare_servers = 12
pm.max_requests = 1000
Restart PHP‑FPM:
sudo systemctl restart php-fpm
Step 4 – Supervisor Configuration
[program:laravel-queue]
process_name=%(program_name)s_%(process_num)02d
command=php /home/youruser/public_html/artisan queue:work redis --sleep=3 --tries=3 --timeout=300
autostart=true
autorestart=true
user=youruser
numprocs=4
redirect_stderr=true
stdout_logfile=/home/youruser/logs/laravel-queue.log
stopwaitsecs=360
Reload Supervisor and start the program:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start laravel-queue:*
numprocs higher than pm.max_children. Doing so will cause PHP‑FPM to spawn more processes than it can handle, leading to OOM kills.Step 5 – Enable Redis Queue Driver (Optional but Powerful)
# Install Redis and php‑redis extension
sudo apt-get install -y redis-server php-redis
sudo systemctl enable redis-server --now
# .env
QUEUE_CONNECTION=redis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
Redis eliminates the MySQL‑related “gone away” errors for queued jobs and dramatically speeds up job dispatch.
VPS or Shared Hosting Optimization Tips
- Use a dedicated MySQL user with only required privileges; it reduces lock contention.
- Enable OPcache in
php.ini(opcache.enable=1,opcache.memory_consumption=256). - Limit Composer autoload to
optimizefor production:composer install --no-dev --optimize-autoloader. - Turn on Cloudflare caching for static assets; set
Cache‑Level: Cache Everythingfor the assets folder. - Schedule a nightly restart of queue workers (via cron) to clear memory leaks:
0 2 * * * php /home/youruser/public_html/artisan queue:restart.
Real World Production Example
Acme SaaS runs a Laravel API on a 2‑core cPanel VPS with 4 GB RAM. After implementing the steps above:
- Queue crash rate dropped from 12/hr to 0.
- Average job latency fell from 7.2 s to 1.3 s.
- MySQL CPU usage fell by 38 % after raising
max_allowed_packetand moving queue to Redis. - Monthly AWS bandwidth bill decreased by 15 % thanks to Cloudflare edge caching.
Before vs After Results
| Metric | Before | After |
|---|---|---|
| Queue Restarts/hr | 12 | 0 |
| Job Latency | 7.2 s | 1.3 s |
| MySQL CPU | 23 % | 14 % |
Security Considerations
- Never run queue workers as
root. Use the same user that owns the Laravel files. - Set
QUEUE_CONNECTION=redisbehind a firewall. Bind Redis to127.0.0.1or useunix socket. - Enable
APP_ENV=productionandAPP_DEBUG=falsein.envto avoid leaking stack traces. - Regularly rotate MySQL passwords and keep
.envout of version control.
Bonus Performance Tips
- Use Horizon for real‑time monitoring:
php artisan horizongives you a dashboard and auto‑scales workers. - Leverage Laravel Octane with Swoole for ultra‑fast queue processing when your VPS supports it.
- Compress large payloads before pushing to the queue (e.g.,
gzcompress()). - Batch DB writes inside jobs (
DB::transaction()) to reduce lock time. - Pin Composer dependencies to avoid unexpected breakages after upgrades.
FAQ
Q: My queue still restarts after applying the steps. What now?
A: Check /home/youruser/logs/laravel-queue.log for fatal errors. Common leftover issue is a missing phpredis.so extension when switching to Redis.
Q: Can I run this on shared hosting without cPanel?
A: Yes, but you’ll need to rely on cron instead of Supervisor and keep pm.max_children low (3‑5). Consider moving to a low‑cost VPS for reliable queues.
Q: Do I need to restart all services after each change?
A: MySQL, PHP‑FPM, and Supervisor must be restarted. Redis only needs a reload if you change its config.
Q: How do I monitor queue health?
A: Install Laravel Horizon or use supervisorctl status. For quick checks, php artisan queue:failed will list failed jobs.
Final Thoughts
Queue stability is not a “nice‑to‑have” feature—it’s the lifeline of any production Laravel or WordPress‑backed SaaS. By tightening MySQL, fixing permissions, and right‑sizing PHP‑FPM, you eliminate the most common crash vectors on a cPanel VPS. Add Redis, Horizon, or Octane for the next performance jump, and you’ll have a queue that runs 24/7 without manual babysitting.
Take the time today to audit those settings; the payoff is measurable uptime, lower server costs, and happier customers.
No comments:
Post a Comment