What the message looks like
2026/10/23 10:02:41 [error] 1234#1234: *9012 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 198.51.100.7, server: cloud.beispiel.de, request: "POST /index.php/apps/files/ajax/upload.php HTTP/2.0"Common causes
- Long-running requests: large uploads, exports, reports, image processing.
- The PHP-FPM pool is full (
pm.max_childrenreached) and new requests wait in line. - Slow or locked database queries.
fastcgi_read_timeoutorproxy_read_timeouttoo low for the use case.- Backend on another host unreachable through network or firewall (connect runs into the timeout).
Check
- Find timeouts in the nginx log
grep 'upstream timed out' /var/log/nginx/error.log | tail -n 20 - Check whether PHP-FPM hits its limit
grep -i 'max_children' /var/log/php8.3-fpm.log - Measure response time precisely
curl -s -o /dev/null -w 'connect=%{time_connect} ttfb=%{time_starttransfer} total=%{time_total}\n' https://cloud.example.com/status.php - Show running slow database queries
mysqladmin -u root -p processlist
Fix
- Fix the cause first: optimise slow queries, add indexes, move long jobs to cron or a queue.
- Raise
pm.max_childrenaccording to RAM (RAM for PHP divided by memory per worker). - Raise timeouts together:
fastcgi_read_timeout 300s;in nginx plusmax_execution_timeandrequest_terminate_timeoutin PHP-FPM. - With reverse proxy chains (load balancer, Docker, CDN), check the timeout on every hop.
- After changes run
nginx -t && systemctl reload nginxandsystemctl reload php8.3-fpm.
FAQ
Should I just set the timeout to 3600 seconds?
No. It hides the problem and ties up workers. Raise timeouts only for specific locations such as upload or export paths.
Why do I get a 504 while PHP keeps running?
nginx only drops the connection to the client. The PHP script continues until max_execution_time or request_terminate_timeout kicks in.