502 Bad Gateway: what it means and how to fix it, step by step
Nginx got no response from PHP-FPM. The five most common causes, how to spot them in the logs, and how to get the site back up.
UptimeMag editorial team · 6 October 2026 · 5 min read

The quickest check, before reading any further
A 502 means: Nginx (or the proxy sitting in front of the site) forwarded the request to whatever generates the page — usually PHP-FPM — and either didn't get a response in time or got an invalid one. The problem is almost never in Nginx itself, but in what's behind it.
The first thing to do, on Ubuntu 24.04 with Nginx and PHP-FPM:
sudo systemctl status php8.3-fpm
sudo tail -n 50 /var/log/nginx/error.log
If the service shows as inactive or failed, you've already found the cause. On cPanel, the FPM service should be checked from WHM, under "Restart Services"; on Plesk, from Tools & Settings → PHP Settings, or from the shell with systemctl status followed by the name of the FPM service for the active PHP version (e.g. plesk-php83-fpm, the number changes depending on the version installed).
The log path used above is the default on Ubuntu and Debian, as confirmed by the official Nginx documentation: for RHEL-, Debian- and Ubuntu-based systems, the path is /var/log/nginx/error.log.
The causes, in order of frequency
1. PHP-FPM has crashed or restarted
This is the most common cause. The master process dies due to a segfault in an extension, a worker crash, or a manual restart that didn't complete successfully.
How to spot it: systemctl status php8.3-fpm --no-pager shows the process status; if it died from a signal, the Active field reports the reason. The exit line can be found in the journal: as shown in a real-world case documented by a technician, the process shows as "failed (Result: signal)" with the main PID killed by SEGV. The details should be looked up with journalctl -u php8.3-fpm -b -n 200.
How to fix it: sudo systemctl restart php8.3-fpm. If it keeps crashing, the problem lies in the PHP code (an unstable extension or a bug), not in the server configuration: you need to isolate the script causing the crash by checking the last request in the log before it happened.
2. Timeout on a slow request
PHP-FPM takes too long to respond (a slow query, an external call that doesn't return) and Nginx closes the connection first.
How to spot it: in the PHP-FPM pool (/etc/php/8.3/fpm/pool.d/www.conf) look for request_slowlog_timeout and slowlog; if they're not set, nothing is being logged. Set them, for example to 5 seconds, and check again after the next occurrence: the slowlog file reports the PHP stack trace showing exactly where the request was stuck when the timeout expired.
How to fix it: increase fastcgi_read_timeout in Nginx and request_terminate_timeout in FPM only if the slowness is legitimate (e.g. a heavy export); otherwise optimise the query or the external call.
3. Out of memory, process killed by the kernel (OOM)
The PHP-FPM worker uses too much RAM, and the Linux kernel kills it to free up memory. The site comes back on its own after a few seconds because FPM spawns a new worker, but in the meantime whoever made that request sees the 502.
How to spot it, on Ubuntu 24.04:
journalctl -k -b | grep -Ei 'oom|out of memory|killed process'
A typical line for this kind of event reports the process killed with "Out of memory", along with the task_memcg indication and the process name php-fpm8.3. If it appears, you have your confirmation.
How to fix it: reduce pm.max_children if it's set too high for the available RAM, or add more RAM or an emergency swap (swap won't fix chronic excessive usage, it only helps absorb spikes).
4. Wrong socket or port in the configuration
Nginx points to a socket or port that FPM isn't listening on: this happens after a PHP version upgrade, a migration, or a pool that's been reconfigured by hand.
How to spot it: compare the fastcgi_pass value in the Nginx vhost with listen in the FPM pool. A classic error documented in a real case is the address already in use: the log error reports "unable to bind listening socket for address '127.0.0.1:9000': Address in use", a sign that two pools or two instances are fighting over the same port. Also check with ls -la /run/php/ that the socket file actually exists.
How to fix it: align the two values and reload both services (nginx -t && systemctl reload nginx, then systemctl reload php8.3-fpm).
5. A plugin or script stuck in a loop
A worker stays busy indefinitely (infinite loop, recursive call, blocking query) and is still "serving" a request when further ones come in: FPM runs out of available workers and new requests either queue up or get a 502.
How to spot it: the FPM log shows a pool exhaustion warning. As several practical guides on service management point out, when the warning "server reached max_children" appears, it means PHP-FPM has run out of available workers. Enable the status page (pm.status_path) to see which URLs are stuck at that moment.
How to fix it: identify and fix the plugin or script responsible (often a WordPress theme or plugin making an external call with no timeout); in the meantime, increase pm.max_children only as a stopgap, not as a solution.
When the problem isn't your server
If the site has a CDN or reverse proxy in front of it (Cloudflare, a load balancer, another Nginx instance) and the 502 only appears when going through that layer, while bypassing the proxy and hitting the origin IP directly works fine, then the fault lies in the proxy or in the network between proxy and origin, not in the application server. In this case, open a ticket with the CDN/proxy provider, attaching: the exact time (with timezone), the requested URL, the origin IP address contacted, and if possible the cf-ray header or equivalent from the 502 response received by the browser: this is the information that allows support to search for the event in their own logs without having to ask you for anything else.
How to verify it's fixed
After taking action, reload the page and watch tail -f /var/log/nginx/error.log in parallel: if no new lines containing "upstream" appear during the refresh, the problem is solved. Keep an eye on journalctl -u php8.3-fpm for a few hours to rule out the service crashing again.
Written with the help of artificial intelligence and checked by the editors (EU AI Act, art. 50).