Nginx 502 Bad Gateway: Quick Fix for PHP-FPM Issues
That 502 error almost always means PHP-FPM crashed or the socket is misconfigured. Here's how to fix it fast.
Yeah, that 502 Bad Gateway is a pain. I've seen it hundreds of times — it's almost always PHP-FPM crapping out or a socket mismatch. Let's get it fixed.
The Quick Fix
First, restart PHP-FPM and check Nginx's error log. Run this:
sudo systemctl restart php8.1-fpm # or php7.4-fpm, whatever version
sudo tail -f /var/log/nginx/error.log
If the log shows "connect() failed (111: Connection refused)" or "Connection reset by peer", PHP-FPM's the culprit. If it's "Connection refused", the service isn't running — check with systemctl status php8.1-fpm.
If you see "upstream sent too big header", that's a different beast — jump to the variations section below.
Why This Works
PHP-FPM runs as a separate process — it handles PHP requests and passes results back to Nginx. When it crashes (out of memory, a misconfigured pool, or just a PHP script that infinite loops), Nginx can't connect and returns 502. A restart clears the bad state. But if it keeps crashing, you've got a deeper problem — let's find it.
Check the PHP-FPM error log too:
sudo tail -f /var/log/php8.1-fpm.log
Look for "WARNING: [pool www] seems busy" or "server reached max_children" — that means your pool's max_children setting is too low. Edit your pool config, usually at /etc/php/8.1/fpm/pool.d/www.conf, and bump up the numbers:
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
Adjust based on your RAM. Each PHP process eats about 30-50MB. On a 4GB server, 50 children is safe.
Less Common Variations
Sometimes the socket path is wrong. Nginx's config points to a Unix socket that doesn't exist or has wrong permissions. Check your Nginx site config:
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
}
Verify that socket file exists: ls -la /run/php/php8.1-fpm.sock. If it's missing, PHP-FPM isn't running. If it's there but permissions are wrong (owned by root instead of www-data), fix it:
sudo chown www-data:www-data /run/php/php8.1-fpm.sock
Another sneaky one: if you're using TCP (like fastcgi_pass 127.0.0.1:9000) instead of a Unix socket, check that PHP-FPM is listening on that port: sudo netstat -tlnp | grep 9000. If nothing shows, your pool config has listen = /run/php/php8.1-fpm.sock — mismatch.
Also, if you see "upstream sent too big header" in the Nginx error log, your PHP app is outputting enormous cookies or headers. Fix it by raising buffer sizes in the Nginx config under the server block:
fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;
proxy_buffer_size 128k;
This is common with WordPress sites that set huge session cookies. Don't bother tweaking kernel parameters — it's always buffer sizes.
Preventing It Long-Term
Set up monitoring. The simplest thing: a cron job that checks if PHP-FPM is running and restarts it if it's dead:
*/5 * * * * /usr/sbin/service php8.1-fpm status || /usr/sbin/service php8.1-fpm restart
Better yet, use systemd's Restart=always in the service file:
sudo systemctl edit php8.1-fpm
# Add:
[Service]
Restart=always
RestartSec=10
Also watch your PHP-FPM log for "max_children reached" — bump it up or optimize your PHP scripts. Disable slow PHP modules (xdebug in production, anyone?) and set pm.max_requests = 200 in the pool config to recycle processes before they leak memory.
One more thing: if you're running on low-memory VPS (like AWS t2.micro), PHP-FPM will OOM. Either increase swap or switch to pm = ondemand in the pool config — it spawns children only when needed.
Was this solution helpful?