Nginx "Upstream Timed Out While Reading Response Header From Upstream"
Quick answer
This error means Nginx gave up waiting for your backend to respond within the configured timeout window — the fix depends on determining whether the backend is...
This error means Nginx gave up waiting for your backend to respond within the configured timeout window — the fix depends on determining whether the backend is genuinely just slow for this specific request and needs more time, or whether it's actually hanging/stuck and needs its own separate investigation rather than simply extending Nginx's patience.
The Problem
A proxied request fails, and Nginx's error log shows:
upstream timed out (110: Connection timed out) while reading response header from upstream,
client: 203.0.113.5, server: example.com, request: "GET /api/report HTTP/1.1",
upstream: "http://127.0.0.1:3000/api/report"
Why It Happens
Nginx's proxy_read_timeout governs how long it waits between successful reads from the upstream response — when this elapses without the backend sending anything further, Nginx gives up and returns an error to the client rather than waiting indefinitely. Common underlying causes:
- The backend is performing genuinely slow, legitimate work (a complex query, an expensive computation) that simply takes longer than the currently configured timeout allows
- The backend is stuck or hanging entirely — deadlocked, waiting on an external dependency that never responds, or caught in an infinite loop — meaning no amount of additional timeout would actually help, since it would never respond regardless of how long Nginx waited
- The backend crashed or became unresponsive mid-request, without properly closing the connection, leaving Nginx waiting for a response that will genuinely never arrive
- Network-level issues between Nginx and the backend (relevant even for connections that appear to be purely local, in containerized or virtualized environments with their own internal networking layers) causing packets to be delayed or lost
The Fix
First, determine whether the backend is genuinely just slow or actually stuck, by testing the same request directly against the backend, bypassing Nginx entirely, and observing whether it eventually completes (even if slowly) or truly never responds at all:
time curl http://127.0.0.1:3000/api/report
If this eventually completes, even after a long wait, the backend is genuinely slow rather than stuck — the appropriate fix is either optimizing the backend operation itself, or, if the delay is legitimately expected for this specific operation, raising proxy_read_timeout to accommodate it:
location /api/ {
proxy_pass http://backend;
proxy_read_timeout 120s;
}
If the direct backend test never completes at all, even after waiting significantly longer than any reasonable timeout, the backend is genuinely hung — no Nginx-side timeout adjustment resolves this, since it addresses a symptom (how long Nginx waits) rather than the actual cause (the backend not responding at all). Investigate the backend directly: check its own logs, its resource usage, and whether it's stuck waiting on some external dependency of its own.
For a backend that's occasionally slow due to legitimate, variable load (rather than consistently or predictably slow), consider whether the timeout should be generous enough to accommodate reasonable worst-case legitimate delays, while still being finite enough to fail relatively promptly for genuinely stuck requests — this is a judgment call specific to your application's actual behavior and acceptable user-facing latency:
location /api/ {
proxy_pass http://backend;
proxy_connect_timeout 5s; # fail fast if backend is unreachable at all
proxy_read_timeout 60s; # allow reasonable time for legitimately slower responses
}
Notice the distinction between proxy_connect_timeout (how long to wait to establish the initial connection — should generally be short, since a backend that can't even be reached quickly is unlikely to ever respond) and proxy_read_timeout (how long to wait for the actual response once connected — can reasonably be longer, accommodating genuinely slow but eventually-completing operations).
If backend hangs are a recurring issue rather than a one-time occurrence, add appropriate timeout handling within the backend application itself (for any external calls or database queries it makes), so the backend fails fast and returns an error response rather than hanging indefinitely — this addresses the root cause more directly than only adjusting Nginx's own patience for waiting on a backend that may itself be waiting indefinitely on something else.
Still Not Working?
If backend response times are inconsistent and hard to predict, rather than continuing to guess at an appropriate fixed timeout value, add monitoring/logging around your backend's actual response time distribution under real production load — understanding the genuine p50/p95/p99 latency for the specific endpoint helps you set a timeout that's appropriately generous for legitimate worst-case scenarios, without being so long that a genuinely stuck request takes an excessive amount of time to be detected and fail, leaving users waiting far longer than necessary for what is, in that specific case, actually a hung request rather than a slow one.