What it means
nginx writes this line to its error.log when it proxies a request (proxy_pass, but also uwsgi_pass and fastcgi_pass) and the upstream closes the TCP connection before sending a complete response header. nginx has nothing to forward, so it returns 502 Bad Gateway.
[error] 1234#1234: *5678 upstream prematurely closed connection while reading response header from upstream, client: 203.0.113.7, server: example.com, request: "GET /api/report HTTP/1.1", upstream: "http://127.0.0.1:3000/api/report"The request and upstream fields tell you which route and which backend to look at.
Common causes
1. The worker was killed mid-request. A crash, an unhandled exception that exits the process, or the Linux OOM killer. Confirm:
sudo dmesg -T | grep -iE "killed process|out of memory"
journalctl -u myapp --since "15 min ago"If the kernel killed it, see how to find what the OOM killer ended.
2. The application server's own timeout fired. Gunicorn kills a worker that stays silent longer than --timeout (30 seconds by default) and logs WORKER TIMEOUT; PHP-FPM does the same with request_terminate_timeout. Confirm:
journalctl -u gunicorn --since "1 hour ago" | grep -i "worker timeout"3. A keep-alive race. With keepalive in the upstream block, nginx reuses idle connections. If the backend closes them sooner (Node.js server.keepAliveTimeout is 5 seconds by default), nginx can send a request on a socket the backend is closing. The errors are rare, random, and often follow quiet periods.
How to fix
- Find the failing request in
error.logand open the backend logs at the same second. - If the process was killed, fix the memory use or the limit before touching nginx.
- If the app server timed out, make the endpoint faster or move the work to a background job. If it is legitimately slow, raise the app server timeout and keep it below nginx's
proxy_read_timeout(60 seconds by default). - For the keep-alive race, make the backend keep idle connections open longer than nginx does (nginx's upstream
keepalive_timeoutis 60 seconds), for exampleserver.keepAliveTimeout = 65000in Node.js. - Test and reload:
sudo nginx -t && sudo systemctl reload nginx, then replay the request withcurl -i.
Is it just you?
If users report 502s but your logs look quiet, check the URL from outside your network with Is my site down?, which tests it from several regions at once.
Get alerted next time
- An HTTP monitor fails as soon as nginx answers 502 instead of the status code you expect (2xx by default, or the exact code you set).
- Each failure is rechecked from your other regions before an outage opens, so one dropped connection does not page anyone.
- A TCP port monitor on the backend port, when it is reachable from outside, tells you whether the app is still listening behind nginx.
FAQ
Is upstream prematurely closed connection an nginx bug? ▼
No. nginx is reporting what the backend did: it accepted the connection, received the request, then closed the socket before a full response header arrived. The cause is almost always on the backend side, a crash, a kill or a timeout in the application server.
What is the difference with while sending to client or while reading upstream? ▼
With while reading response header from upstream, no header arrived and the client gets a 502. With while reading upstream or while sending to client, the header and part of the body were already sent, so the client receives a truncated response instead of a clean 502. The causes are the same.
Should I just raise proxy_read_timeout? ▼
Not for this message. proxy_read_timeout governs how long nginx waits, and here nginx did not give up: the backend closed the connection first. Look at the application server's own timeout and at whether the process was killed.