How to Fix 502 Bad Gateway on Nginx
In this article12 sections
A 502 Bad Gateway from Nginx means Nginx itself is working, but the program behind it, usually PHP-FPM or a Node.js or Python app, did not give it a valid answer. The fix is never in the browser. Run sudo tail -n 20 /var/log/nginx/error.log on the server: the last line names the exact failure, such as a missing socket, a refused connection or a crashed worker, and each of those has one specific cause.
This guide is for Ubuntu and Debian servers running Nginx. It lists the error-log messages you will actually see, what each one means and how to fix it, and ends with the difference between 502 and its neighbours 503 and 504.
Step 1: Read the error log
sudo tail -n 20 /var/log/nginx/error.log
If your site has its own log file, set by error_log in its server block, read that one instead. Reload the failing page once, then run the command again so the newest line is yours. It will look like this:
2026/10/14 09:12:44 [crit] 1201#1201: *87 connect() to unix:/run/php/php8.1-fpm.sock failed (2: No such file or directory) while connecting to upstream, client: 203.0.113.9, server: example.com, request: "GET / HTTP/2.0", upstream: "fastcgi://unix:/run/php/php8.1-fpm.sock:", host: "example.com"
The part in brackets after failed or the phrase before while is what matters. Find it in this table:
| The log says | Meaning | Go to |
|---|---|---|
(2: No such file or directory) |
The socket file Nginx was told to use does not exist | Fix 1 |
(111: Connection refused) |
Nothing is listening at that address or port | Fix 1 or Fix 4 |
(13: Permission denied) |
Nginx is not allowed to open the socket | Fix 2 |
recv() failed (104: Connection reset by peer) |
The worker died while handling the request | Fix 3 |
upstream prematurely closed connection |
The worker stopped before answering | Fix 3 |
upstream sent too big header |
The response headers did not fit in Nginx’s buffer | Fix 5 |
(11: Resource temporarily unavailable) |
Every worker is busy and the queue is full | Fix 6 |
Fix 1: PHP-FPM is not running, or Nginx points at the wrong version
This is the most common cause, and it usually appears right after a system upgrade. Compare what Nginx is asking for with what exists:
grep -R "fastcgi_pass" /etc/nginx/sites-enabled/
ls -l /run/php/
systemctl list-units 'php*-fpm*' --no-pager
If Nginx asks for php8.1-fpm.sock and the folder contains only php8.3-fpm.sock, the PHP version changed under you: an upgrade installed 8.3 and removed 8.1. Edit the fastcgi_pass line in the site’s configuration to the socket that exists, then test and reload:
sudo nginx -t && sudo systemctl reload nginx
If the socket name is right but the service is not running, start it and read why it stopped:
sudo systemctl start php8.3-fpm
sudo journalctl -u php8.3-fpm -n 30 --no-pager
A service that refuses to start almost always has a mistake in a pool file. sudo php-fpm8.3 -t names the file and line.
Fix 2: Permission denied on the socket
The socket exists, but the user Nginx runs as may not open it. Check both sides:
ls -l /run/php/
grep -E "^user" /etc/nginx/nginx.conf
grep -E "^listen\.(owner|group|mode)" /etc/php/8.3/fpm/pool.d/*.conf
The pool’s listen.owner and listen.group must be the user Nginx runs as, which is www-data on Ubuntu, with listen.mode = 0660. Correct the pool file, then restart PHP-FPM so the socket is created again with the new owner:
sudo systemctl restart php8.3-fpm
Fix 3: The worker crashed
If the log says the connection was reset or closed early, a PHP worker died in the middle of the request. Two logs say why:
sudo journalctl -k --since "1 hour ago" | grep -iE "out of memory|killed process|segfault"
sudo tail -n 30 /var/log/php8.3-fpm.log
Out of memory: Killed process ... (php-fpm8.3)means the server ran out of RAM. There are more workers than the memory can hold. Lowerpm.max_childrenusing the method in how to optimize PHP-FPM workers for limited RAM, and add swap space as a cushion.segfaultorexited on signal 11means PHP itself crashed, nearly always because of a faulty extension or a stale OPcache after an update. Restart PHP-FPM. If it returns, disable the extensions you added most recently, one at a time.execution timed out ... terminatingmeans the request ran longer thanrequest_terminate_timeoutand PHP-FPM killed it. Find the slow code with the slow log before raising the limit.
If the 502 appears only on one page, such as an import or a report, it is this cause: that page uses more memory or time than the rest.
Fix 4: A Node.js, Python or other app behind proxy_pass
When Nginx forwards to an application with proxy_pass, a refused connection means the app is not listening where Nginx expects:
grep -R "proxy_pass" /etc/nginx/sites-enabled/
sudo ss -tlnp | grep -E ":(3000|5678|8000|8080)"
curl -sI http://127.0.0.1:3000/ | head -1
Use your own port in the last two commands. If nothing is listening, the app is down: check it with systemctl status your-app, pm2 status or docker ps, and read its own log. If something is listening but on a different port or only on IPv6, make the proxy_pass address match exactly. Writing http://127.0.0.1:3000 rather than http://localhost:3000 avoids a common trap, where localhost resolves to the IPv6 address and the app listens only on IPv4.
Fix 5: Upstream sent too big header
The application answered, but its headers, usually a large set of cookies after login, did not fit in the 4 or 8 KB that Nginx reserves by default. Give it more room. For PHP, inside the location ~ \.php$ block:
fastcgi_buffer_size 32k;
fastcgi_buffers 16 16k;
fastcgi_busy_buffers_size 64k;
For an app behind proxy_pass, the same three settings begin with proxy_ instead of fastcgi_. Test and reload Nginx. This is the usual answer when a 502 appears only for logged-in users.
Fix 6: All workers are busy
If the 502 comes in bursts under load, look for this line in the PHP-FPM log:
WARNING: [pool www] server reached pm.max_children setting (5), consider raising it
Requests are queueing, and when the queue fills, new ones are turned away. Raising the number helps only if you have the memory for more workers. Measure first, as described in the PHP-FPM guide linked above. More often the lasting fix is to make each request cheaper: a page cache so most visits never reach PHP, and a look at whatever plugin or query is slow.
502, 503 or 504?
| Code | Who is reporting | What it means |
|---|---|---|
| 502 Bad Gateway | Nginx | The program behind it gave no valid answer: down, crashed or unreachable |
| 503 Service Unavailable | Nginx or the app | Deliberately refusing: maintenance mode, rate limiting, no healthy backend |
| 504 Gateway Timeout | Nginx | The program behind it is running but took too long |
A 504 means the backend is alive and slow, so the question is what the request is doing. A 502 means there was no usable answer at all, so the question is whether the backend is there.
If Cloudflare shows the 502
Look at the error page. If it carries Cloudflare’s branding and a Ray ID, Cloudflare could not get an answer from your server, and everything above still applies: check the server. If the page is plain and says nginx at the bottom, the response came from your own Nginx through Cloudflare, which is the case this guide covers. To take Cloudflare out of the picture while testing, ask your server directly:
curl -sI --resolve example.com:443:YOUR.SERVER.IP https://example.com/ | head -1
Common mistakes to avoid
- Restarting everything and moving on. It works until the cause returns. Read the log line first: it takes ten seconds.
- Raising timeouts for a 502. Timeouts are a 504 matter. A 502 is about a missing or dead backend.
- Raising
pm.max_childrenon a server that is out of memory. That causes more crashes, not fewer. - Upgrading Ubuntu or PHP without checking
fastcgi_pass. The old socket path disappears with the old version. - Clearing the browser cache. The browser has nothing to do with it.
A server with room to breathe
Most 502 errors that keep coming back are a server short of memory. Every SiteHarbour VPS has reserved CPU and RAM on NVMe storage, so what you tune is yours and stays the same from one hour to the next, and our engineers install and test your stack before handover. You can move to a larger plan later without migrating to a new server.
Frequently asked questions
Is a 502 error my fault or the website’s?
The website’s. It is a server-side error, and nothing a visitor does causes or fixes it.
Why does the 502 fix itself after a few minutes?
The service restarted by itself after a crash, or the load dropped. It will come back under the same conditions, so use the quiet moment to read the logs.
Why do I get 502 only in wp-admin?
Admin pages are not cached and use more memory and larger cookies than public pages. Check Fix 3 for memory and Fix 5 for header size.
Can a plugin cause 502 Bad Gateway?
Yes, indirectly: by using enough memory to get the worker killed, or by running until PHP-FPM terminates it. The PHP-FPM log shows which script was running.
Where is the Nginx error log?
/var/log/nginx/error.log by default. A site can have its own, set with error_log in its server block, so check there too.
The short version: a 502 is Nginx telling you the backend did not answer. The last line of the error log says how it failed, and that phrase points to one of six fixes.