How to Fix 502 Bad Gateway in Nginx and PHP-FPM
Diagnose a 502 Bad Gateway between Nginx and PHP-FPM by checking logs, sockets, services, permissions, capacity, and timeouts in the right order.
A 502 is a boundary failure: identify the failing upstream in the Nginx error log, then verify the PHP-FPM service, socket or port, permissions, and resource limits before changing timeouts.
A 502 Bad Gateway from Nginx means the proxy received an invalid response—or no usable response—from its upstream. In a PHP application, that upstream is usually PHP-FPM. The browser only shows the boundary error; the useful evidence is in the Nginx and PHP-FPM logs.
Do not begin by increasing every timeout. First determine whether Nginx cannot connect, PHP-FPM is crashing, or the application is taking too long.
Confirm which upstream failed
Reproduce the request once, record its time and path, and inspect the relevant logs immediately:
sudo tail -n 100 /var/log/nginx/error.log
sudo journalctl -u php8.3-fpm --since "10 minutes ago"
sudo systemctl status php8.3-fpm --no-pager
Replace php8.3-fpm with the installed service name. You can list likely units with:
systemctl list-units --type=service | grep -E 'php.*fpm'
Common Nginx messages point to different causes:
No such file or directoryusually means the configured Unix socket path is wrong.Permission deniedmeans Nginx cannot access the socket or a parent directory.Connection refusedmeans nothing is listening on the configured port or socket.upstream timed outmeans Nginx connected, but PHP-FPM did not send data within the configured interval.upstream prematurely closed FastCGI stdoutoften accompanies a PHP crash, fatal error, process termination, or resource exhaustion.
If the response came from another proxy or CDN, confirm that the visible 502 is actually produced by your Nginx host before changing PHP-FPM.
Validate Nginx and PHP-FPM separately
Check the Nginx configuration before reloading it:
sudo nginx -t
sudo systemctl status nginx --no-pager
Then verify that PHP-FPM is active:
sudo systemctl is-active php8.3-fpm
sudo systemctl restart php8.3-fpm
A restart can restore service, but it is not a diagnosis. Read the journal after restarting so you know whether the process failed because of an invalid pool configuration, missing extension, memory pressure, or another repeatable condition.
If PHP-FPM will not start, validate its configuration using the binary available on your server:
sudo php-fpm8.3 -tt
Package names and binary paths vary by distribution. Use command -v php-fpm8.3 or inspect the service unit when unsure.
Match the FastCGI socket or port
The fastcgi_pass value in Nginx must match the listener configured by the PHP-FPM pool.
An Nginx Unix-socket configuration might contain:
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
Compare it with the pool configuration, commonly under /etc/php/8.3/fpm/pool.d/www.conf:
listen = /run/php/php8.3-fpm.sock
Inspect listeners without guessing:
sudo ss -ltnp | grep php
sudo find /run/php -maxdepth 1 -type s -ls
For TCP, both sides must use the same address and port, such as 127.0.0.1:9000. Avoid exposing PHP-FPM on a public interface.
After changing configuration:
sudo nginx -t && sudo systemctl reload nginx
sudo systemctl restart php8.3-fpm
Fix socket permissions deliberately
When the log says Permission denied, check the socket ownership and the user running Nginx:
ps -o user,group,cmd -C nginx
sudo stat /run/php/php8.3-fpm.sock
Configure the pool rather than applying a temporary chmod that disappears after restart:
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
The correct user differs across distributions. Parent directories also need traversal permission. Do not solve the problem with mode 0777; that makes the boundary unnecessarily writable.
Check capacity, crashes, and slow application work
If connections work under light traffic but fail during load, inspect memory, disk, and PHP-FPM pool saturation:
free -h
df -h
sudo dmesg -T | grep -i -E 'out of memory|killed process'
sudo journalctl -u php8.3-fpm -p warning --since today
Review pm.max_children, pm.max_requests, and the pool process manager against measured memory use. Raising pm.max_children without available RAM can make the kernel kill PHP workers and create more 502 responses.
For slow requests, enable the PHP-FPM slow log temporarily and profile the application. Database locks, external API calls, filesystem latency, and synchronous report generation are usually better fixed at their source. Long work should often move to a queue; see the Laravel queue and Supervisor troubleshooting guide.
Nginx documents fastcgi_read_timeout as the interval between successive reads from FastCGI, not a total request-duration limit. Increase it only when a legitimate endpoint is expected to remain silent for longer, and keep the scope narrow.
Verify the fix
Test both a simple PHP route and the path that originally failed:
curl -sS -o /dev/null -w '%{http_code} %{time_total}\n' https://example.com/health
curl -sS -o /dev/null -w '%{http_code} %{time_total}\n' https://example.com/original-path
Then confirm:
nginx -tsucceeds.- Nginx and PHP-FPM remain active after several requests.
- The error log does not receive a new upstream failure.
- A deployment restart does not recreate the socket mismatch.
- Monitoring sees both the public endpoint and the PHP-FPM service.
Common mistakes and prevention
Avoid these shortcuts:
- Raising all timeouts before reading the error log.
- Pointing Nginx at a socket from an older PHP version.
- Starting
php artisan serveas a production upstream. - Changing socket permissions manually instead of fixing the pool.
- Restarting services repeatedly without checking why they stopped.
- Hiding a capacity problem by creating more PHP-FPM children than memory allows.
Keep the Nginx and PHP-FPM configuration in version control, validate both during deployment, and monitor service state, error rate, memory pressure, and upstream response time. The broader Nginx reverse proxy production checklist covers the surrounding boundary.
Frequently asked questions
Is the problem fixed if restarting PHP-FPM removes the 502?
Service is restored, but the cause is not necessarily fixed. Check the preceding journal entries, memory pressure, pool limits, and deployment events so the same failure does not return.
Should Nginx connect to PHP-FPM through a Unix socket or TCP?
Both can work. A Unix socket is common when both services share a host; TCP is often clearer across containers. The important requirements are a private listener, matching configuration, controlled permissions, and monitoring.
Official references
Have a question about this guide or an idea for a technical collaboration? Contact Bakry through the Dev Hub.
End of field note.