Skip to content
← All articles

HTTP 504 Gateway Timeout: Causes and Solutions for Sysadmins

The 504 Gateway Timeout error happens when a proxy (nginx, Cloudflare) waits for an upstream response longer than its timeout allows. Unlike 502 (invalid response), 504 is expiry of a wait. Let us cover the causes, how to configure timeouts correctly, and how to optimize slow requests instead of just hiding them.

What 504 Means

Per RFC 9110 §15.6.5, 504 means the server, acting as a gateway, did not get a timely response from upstream. The key word is "timely" — the timeout is configured on the proxy.

6 Common Causes

  1. Slow SQL query without an index, blocking a transaction.
  2. Slow external API документацию that depends on a third party.
  3. Suboptimal code — N+1 queries, un-массовую проверку URL operations.
  4. Heavy work inside the request/response cycle (PDF generation, sending emails).
  5. Low timeout in nginx/Cloudflare for legitimately long operations.
  6. Upstream stuck — database deadlock, blocked thread.

Diagnosing Slow Requests

# Top slow requests in access.log
awk '$10 > 5' /var/log/nginx/access.log | head -20

# MySQL slow log
mysqldumpslow -t 10 /var/log/mysql/slow.log

# PHP-FPM slow log
# /etc/php/8.4/fpm/pool.d/www.conf:
# slowlog = /var/log/php/www-slow.log
# request_slowlog_timeout = 5s
tail -100 /var/log/php/www-slow.log

# Node.js: event loop lag
// npm install clinic
// clinic doctor -- node app.js

Check external response time via Enterno.io PageSpeed Check — get TTFB, Web Vitals, and bottlenecks.

Proper nginx Timeout Configuration

http {
    # Connection to upstream
    proxy_connect_timeout 10s;

    # Sending request upstream
    proxy_send_timeout 30s;

    # Reading upstream response
    proxy_read_timeout 60s;

    # For FastCGI (PHP-FPM)
    fastcgi_connect_timeout 10s;
    fastcgi_send_timeout 30s;
    fastcgi_read_timeout 60s;
}

# Long-polling endpoint — dedicated location
location /api/long-poll {
    proxy_read_timeout 300s;  # 5 minutes
    proxy_pass http://backend;
}

PHP-FPM: max_execution_time

# php.ini
max_execution_time = 30
max_input_time = 60

# For large data exports:
# Set per-request via ini_set()
ini_set('max_execution_time', 300);  # 5 minutes
set_time_limit(300);

# But better — move to a queue!

Node.js: Server Timeout

const server = app.listen(3000);
server.setTimeout(60000);  // 60 seconds
server.keepAliveTimeout = 61000;
server.headersTimeout = 65000;  // must be > keepAliveTimeout

// For Fastify
const app = Fastify({
  connectionTimeout: 60000,
  keepAliveTimeout: 61000,
});

Right Solution: Offload to Background

Raising timeouts forever is an anti-pattern. The right solution is offloading long operations to a queue.

// Bad: blocks the request
app.post('/generate-report', async (req, res) => {
  const pdf = await generateBigPDF(req.body);  // 3 minutes
  await sendEmail(pdf);
  res.json({ok: true});
});

// Good: queue + notification
app.post('/generate-report', async (req, res) => {
  const jobId = await queue.add('generate-report', req.body);
  res.status(202).json({jobId, status: 'queued'});
});

// Worker processes in background
queue.process('generate-report', async (job) => {
  const pdf = await generateBigPDF(job.data);
  await sendEmail(pdf);
});

The client receives 202 Accepted + jobId and polls /jobs/:id or gets a WebSocket/webhook notification.

Optimizing Slow DB Queries

-- Find long queries
SHOW PROCESSLIST;
SHOW FULL PROCESSLIST;

-- EXPLAIN a query plan
EXPLAIN SELECT * FROM orders WHERE user_id = 1 ORDER BY created_at DESC LIMIT 10;

-- Add an index if needed
CREATE INDEX idx_orders_user_created ON orders(user_id, created_at DESC);

-- Check table sizes
SELECT table_name, ROUND(data_length/1024/1024) AS mb
FROM information_schema.tables
WHERE table_schema = 'your_db'
ORDER BY data_length DESC LIMIT 10;

Cloudflare 504 — Specifics

Cloudflare has a hard 100-second limit on free/pro plans. Options:

Frequently Asked Questions

Q: How does 504 differ from 502?
A: 504 — upstream did not respond in time. 502 — upstream responded invalidly or closed the connection.

Q: What timeout is adequate?
A: Web requests: 30-60s. APIs: 10-30s. Long-polling: 300+s. Long-running tasks: move to a queue.

Q: How to detect 504 automatically?
A: Enterno.io Monitors with short timeouts trigger alerts. Also add APM (Sentry, New Relic).

Q: Does 504 affect SEO?
A: Yes, critically. Googlebot has its own timeout (~30s). Systematic 504s cause deindexing.

Conclusion

504 is not a timeout bug — it is a symptom of slow code or a slow external API. Monitor the slow log, optimize queries, offload long work to a queue. Set timeouts generously but not infinitely. Hook up Enterno.io to automatically catch 504s across regions.

Check your website right now

Check now →
More articles: HTTP
HTTP
Analyzing Server Response Headers: What They Reveal About a Website
11.03.2026 · 41 views
HTTP
HTTP Methods Explained: GET, POST, PUT, DELETE and Beyond
16.03.2026 · 89 views
HTTP
HTTP Redirect Chains and Their Impact on SEO
15.04.2026 · 6 views
HTTP
HTTP 503 Service Unavailable: Causes and Solutions
15.04.2026 · 5 views