Error fix · Server errors

nginx "upstream timed out (110: Connection timed out)" Fix

Decode the nginx log line "upstream timed out (110: Connection timed out)" and set the right timeout directive for PHP-FPM, proxy_pass or uWSGI.

Error messageupstream timed out (110: Connection timed out) while reading response header from upstream

By SiteDownCheck Editorial · Updated October 5, 2026 · 4 min read

This line in the nginx error log means nginx forwarded a request to a backend (PHP-FPM, Node, Gunicorn, another web server) and the backend did not answer within the configured timeout, so nginx gave up. The visitor receives a 504 Gateway Timeout. The log line is more useful than the 504 because it tells you which stage timed out.

You find it in /var/log/nginx/error.log:

2026/10/05 10:12:01 [error] 1234#1234: *5678 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 203.0.113.9, server: example.com, request: "POST /checkout HTTP/1.1", upstream: "fastcgi://unix:/run/php/php8.2-fpm.sock", host: "example.com"

For the general 504 picture, see Fix 504 Gateway Timeout. This page focuses on reading the log line and setting the right directive.

Read the phrase after "while"

The text after "while" says which phase timed out, and each phase has its own directive:

Log phraseMeaningDirective (default)
while connecting to upstreamCould not establish the connection in timeproxy_connect_timeout / fastcgi_connect_timeout (60s)
while reading response header from upstreamConnected, but no response headers arrivedproxy_read_timeout / fastcgi_read_timeout (60s)
while reading upstreamHeaders arrived, then the body stalledsame read timeout
while sending request to upstreamBackend stopped accepting the requestproxy_send_timeout / fastcgi_send_timeout (60s)

Read timeouts are measured between two successive reads, not over the whole response. A backend that sends a byte every 30 seconds will not trip a 60 second read timeout.

Causes, most likely first

  1. A slow request in the backend. A heavy report, an unindexed database query, a slow external API call or a large export takes longer than 60 seconds.
  2. Backend overloaded or out of workers. All PHP-FPM children are busy and requests queue until nginx times out.
  3. Backend hung or deadlocked, often waiting on a database lock or an external service.
  4. Timeout too low for a legitimate long job such as an import.
  5. Connect-phase problems: a firewall dropping packets to a remote upstream, or a wrong address.

Fix 1: find out why the backend is slow first

Raising timeouts hides slowness. Check the backend:

# PHP-FPM: slow log and status
sudo grep -E "pm.max_children|request_slowlog_timeout|slowlog" /etc/php/8.2/fpm/pool.d/www.conf
sudo tail -n 50 /var/log/php8.2-fpm.log      # look for "server reached pm.max_children"

Enable the slow log in the pool config to get a stack trace of requests running longer than a threshold:

request_slowlog_timeout = 10s
slowlog = /var/log/php8.2-fpm.slow.log

If the log says the server reached pm.max_children, raise it only as far as your RAM allows (average process memory times max children must fit), and fix the slow code that holds workers.

Fix 2: raise the right timeout for the right location

Apply long timeouts only to the endpoint that needs them, not globally.

PHP-FPM (fastcgi):

location = /admin/export.php {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    fastcgi_read_timeout 300s;
}

Reverse proxy to Node, Gunicorn, another server:

location /api/reports/ {
    proxy_pass http://127.0.0.1:3000;
    proxy_read_timeout 300s;
    proxy_connect_timeout 5s;
}

uWSGI: uwsgi_read_timeout 300s;

Then test and reload:

sudo nginx -t && sudo systemctl reload nginx

Check those too:

php -i | grep max_execution_time
grep -n request_terminate_timeout /etc/php/8.2/fpm/pool.d/www.conf

Fix 3: move long work out of the request

For anything that routinely takes over a minute, return quickly and process in the background: put the job on a queue, return 202 Accepted with a status URL, and let the browser poll. Exports and imports are the classic cases.

Fix 4: for connect-phase timeouts

If the log says "while connecting to upstream", test the path to the backend:

curl -v --max-time 5 http://10.0.0.8:3000/health

Check firewall rules between hosts and security groups, and use the Port Checker to confirm a public port is reachable. If the log says "connection refused (111)" instead, that is a different problem, see nginx connect() failed (111). Keep proxy_connect_timeout short, a few seconds, so failures surface quickly.

How to verify

Repeat the slow request with timing:

curl -o /dev/null -s -w "status=%{http_code} time=%{time_total}s\n" https://example.com/admin/export.php

Then check the error log has no new upstream timed out lines (sudo tail -f /var/log/nginx/error.log). Use the HTTP Status Checker and Website Speed Test from outside your network, and see nginx 502 and 504 timeout tuning for the full tuning picture.

Next steps

FAQ

Why does the client see 504 and not the log message?

nginx converts upstream timeouts into a 504 response for the visitor, while the precise cause goes only to the error log.

Is the default timeout 60 seconds everywhere?

For the nginx proxy, FastCGI, uWSGI and SCGI read, send and connect directives the documented default is 60 seconds. The backend, a CDN or a load balancer in front may have different limits, so check each hop.

Will a bigger timeout fix it permanently?

Only if the work is legitimately long. If a request normally takes 2 seconds and now takes 70, a longer timeout hides a real performance problem.

Does Cloudflare time out earlier?

Cloudflare has its own proxy read timeout, 100 seconds by default, after which it shows a 524. See Cloudflare 520 to 526 errors.

Get notified when this fix updates

Plus occasional practical tips on uptime and monitoring, nothing else. Unsubscribe anytime.

This page is general information written by our editorial team and updated when documentation changes. Servers and providers differ, so test changes safely first. See our editorial policy and disclaimer.