Introduction
The Nginx "upstream timed out" error occurs when Nginx acts as a reverse proxy to PHP-FPM via FastCGI and the backend fails to respond within the configured timeout window. This manifests as a 504 Gateway Timeout in the browser, and the Nginx error log records a message like:
2026/04/08 14:23:01 [error] 1234#0: *5678 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 192.168.1.50, server: example.com, request: "POST /api/import HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "example.com"Symptoms
- Browser displays 504 Gateway Timeout after approximately 60 seconds
- Nginx error log shows "upstream timed out (110: Connection timed out) while reading response header from upstream"
- PHP-FPM process may still be running the script even after Nginx returns the error
- Slow-running scripts (database imports, report generation) consistently trigger the timeout
- The error appears only for specific long-running endpoints, not site-wide
Common Causes
fastcgi_read_timeoutdefault value of 60s is too short for long-running PHP scripts- PHP
max_execution_timeset higher than Nginx's FastCGI timeout, causing PHP to keep working while Nginx has already timed out - PHP-FPM pool
request_terminate_timeoutkilling the process before script completion - Database queries or external API calls within PHP taking longer than expected
- Insufficient PHP-FPM child processes causing request queuing
Step-by-Step Fix
- 1.Increase FastCGI read timeout in Nginx server block:
- 2.```nginx
- 3.server {
- 4.listen 80;
- 5.server_name example.com;
- 6.root /var/www/html;
- 7.index index.php;
location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params;
# Increase timeout for long-running requests fastcgi_read_timeout 300s; fastcgi_send_timeout 300s; fastcgi_connect_timeout 60s; fastcgi_buffer_size 128k; fastcgi_buffers 4 256k; fastcgi_busy_buffers_size 256k; } } ```
- 1.Align PHP max_execution_time with Nginx timeout. Edit
/etc/php/8.2/fpm/php.ini: - 2.```ini
- 3.max_execution_time = 300
- 4.
` - 5.This ensures PHP does not terminate before Nginx times out, or vice versa.
- 6.Verify PHP-FPM pool settings in
/etc/php/8.2/fpm/pool.d/www.conf: - 7.```ini
- 8.request_terminate_timeout = 300s
- 9.
` - 10.This setting overrides
max_execution_timein PHP-FPM and must also be increased. - 11.Test and reload configurations:
- 12.```bash
- 13.sudo nginx -t
- 14.sudo systemctl reload nginx
- 15.sudo systemctl reload php8.2-fpm
- 16.
` - 17.Verify the fix by monitoring the Nginx error log during a long-running request:
- 18.```bash
- 19.sudo tail -f /var/log/nginx/error.log | grep "upstream timed out"
- 20.
` - 21.If no timeout messages appear during the previously failing request, the fix is successful.
Prevention
- Monitor PHP-FPM slow log by enabling it:
slowlog = /var/log/php-fpm/slow.logandrequest_slowlog_timeout = 5sin the pool configuration - Set up alerting on 504 response rates using Nginx access log parsing
- Profile long-running PHP scripts with Xdebug or Blackfire to identify optimization opportunities
- Offload batch processing to background job queues (e.g., Laravel Horizon, Symfony Messenger) instead of HTTP requests
- Use
fastcgi_next_upstream timeoutif you have multiple PHP-FPM backends for automatic failover