error http

HTTP 504 Gateway Timeout

Understanding HTTP 504 Gateway Timeout - the server acting as a gateway did not receive a timely response from the upstream server.

What It Means

HTTP 504 Gateway Timeout indicates that the server, while acting as a gateway or proxy, did not receive a timely response from the upstream server it needed to access to complete the request.

This is different from 408 Request Timeout, where the client was too slow. In 504, the client’s request reached the proxy, but the backend application server took too long to respond.

Common Causes

  • Slow database queries blocking the response
  • Long-running computations or data processing
  • Upstream server is overloaded and cannot respond in time
  • Network connectivity issues between proxy and application server
  • DNS resolution delays
  • External API calls timing out
  • Deadlocks in application code
  • Proxy timeout configuration is too short for the operation

How to Fix

Increase proxy timeout settings

# Nginx - increase upstream timeouts
location /api/ {
    proxy_pass http://backend;
    proxy_connect_timeout 300s;
    proxy_send_timeout 300s;
    proxy_read_timeout 300s;
    send_timeout 300s;
}

# For FastCGI (PHP-FPM)
location ~ \.php$ {
    fastcgi_read_timeout 300s;
}

AWS ALB/ELB timeout

# Increase ALB idle timeout (default 60s)
aws elbv2 modify-load-balancer-attributes \
  --load-balancer-arn <arn> \
  --attributes Key=idle_timeout.timeout_seconds,Value=300

Optimize slow queries

-- Find slow queries in PostgreSQL
SELECT pid, now() - pg_stat_activity.query_start AS duration, query
FROM pg_stat_activity
WHERE state != 'idle'
ORDER BY duration DESC;

-- Find slow queries in MySQL
SELECT * FROM information_schema.processlist
WHERE command != 'Sleep'
ORDER BY time DESC;

-- Add indexes to speed up queries
EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 123;
CREATE INDEX idx_orders_user_id ON orders(user_id);

Move long operations to background jobs

// Instead of processing in the request handler
app.post('/api/reports/generate', async (req, res) => {
  // Bad: This might take minutes
  // const report = await generateHugeReport(req.body);

  // Good: Queue the job and return immediately
  const jobId = await queue.add('generateReport', req.body);
  res.status(202).json({
    message: 'Report generation started',
    jobId,
    statusUrl: `/api/reports/status/${jobId}`
  });
});

// Polling endpoint for job status
app.get('/api/reports/status/:jobId', async (req, res) => {
  const job = await queue.getJob(req.params.jobId);
  res.json({
    status: job.status,
    progress: job.progress,
    result: job.status === 'completed' ? job.result : null
  });
});

Client-side handling

async function fetchWithTimeout(url, timeoutMs = 30000) {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);

  try {
    const response = await fetch(url, { signal: controller.signal });
    clearTimeout(timeoutId);
    return response;
  } catch (error) {
    if (error.name === 'AbortError') {
      console.error('Request timed out');
    }
    throw error;
  }
}
  • HTTP 502 - Bad Gateway: The upstream server returned an invalid response, rather than no response.
  • HTTP 503 - Service Unavailable: The server is temporarily overloaded or under maintenance.
  • HTTP 408 - Request Timeout: The client was too slow to send the request.