503 Service Unavailable: causes and fixes

  • http-errors

A 503 is deliberate. Unlike a 502 (something upstream broke) or a timeout (something vanished), a 503 is software choosing to refuse work: “I’m here, I’m not serving you right now.” Finding out which software made that choice is the whole diagnosis.

What sends a 503, and why?

Three suspects cover nearly every case:

  • A load balancer with no healthy backends. Every app instance is failing its health check, so the balancer has nobody to send you to. The instances may even be “running” — just not answering the health endpoint in time.
  • The application’s own overload guard. Many frameworks and WAFs shed load with 503s when queues fill up. The site often flickers: fine, 503, fine.
  • Maintenance mode someone forgot to turn off. Deployment tools ship it; humans forget it. If the 503 page looks branded and tidy, suspect this first.

How do I tell overload from maintenance?

Look at the pattern, not one request:

# Ten requests, two seconds apart — is it every request or a fraction?
for i in $(seq 1 10); do curl -s -o /dev/null -w '%{http_code}\n' https://example.com; sleep 2; done

Every single request 503ing usually means maintenance mode or zero healthy backends. A mix of 200s and 503s means load shedding — some requests find capacity, some don’t. Also check the Retry-After response header; well-behaved maintenance pages set it.

What do I check on the server?

# Are the app instances passing their own health check?
curl -sI http://127.0.0.1:3000/healthz

# What does the balancer think? (nginx upstream health, HAProxy stats,
# or your cloud console's target-group health tab)
tail -f /var/log/nginx/error.log

If health checks fail while the app “works”, the health endpoint itself is often the bug — too slow under load, or checking a dependency that’s down even though the app could serve degraded traffic.

How long will a 503 last?

Overload 503s end when traffic drops or capacity arrives. Maintenance 503s end when someone remembers. That second category is why external monitoring earns its keep: the deploy finished at 17:40, the maintenance flag stayed on, and nobody in the office typed the URL again until morning. YoPingMe checks from three regions on a schedule and yells on email, webhook, or Slack when all three agree — 10 monitors free, first check during signup.