503 Service Unavailable
503 Service Unavailable means the server, or a proxy in front of it, is temporarily unable to handle the request: it is overloaded, in maintenance, or has no healthy backend to send it to. It is meant to be temporary.
The server is temporarily unable to handle the request, from overload or maintenance.
It signals a temporary condition, and the server may send Retry-After to say when to come back. Load balancers return it when no healthy backend is available, and nginx returns it by default when limit_req or limit_conn rejects a request. Search engines treat a short-lived 503 as downtime rather than a removed page.
Explained
Unlike 502 and 504, a 503 is often a deliberate decision. A load balancer sends it when every backend fails its health checks or none is registered. An app sends it in maintenance mode or when it sheds load. nginx sends it by default when limit_req or limit_conn rejects a request.
The server can include Retry-After to say when to try again. Search engines treat a brief 503 as temporary downtime and keep the page indexed, which makes it the right status for planned maintenance; a maintenance page served with 200 can replace your content in search results.
In Kubernetes, an ingress controller returns 503 when the Service has no ready endpoints: the pods are failing readiness probes, the selector does not match the pod labels, or the deployment is scaled to zero.
How to debug it
- Identify who sent the 503: the response body, a
Serverheader or the proxy's log usually make it obvious. - If it is a load balancer, check target health and the health check path, port and expected status code.
- In Kubernetes, run
kubectl get endpoints <service>; an empty list means no pod is ready or the selector is wrong. - If it is nginx, look for
limiting requestsin the error log, which points tolimit_req. - Check resource saturation on the backends: CPU, memory, connection pools, thread or worker counts.
Gotchas
- A health check endpoint that queries the database can take the whole service out of rotation when the database is slow, turning a slowdown into a full outage.
- nginx's default 503 for rate limiting confuses clients expecting 429; set
limit_req_status 429;. - Clients should retry a 503 with backoff, not immediately.
Related explainers
- 502 Bad GatewayA 502 means a proxy got no valid reply from the app behind it. How to read nginx's error log, common...
- 504 Gateway TimeoutA 504 means a proxy waited too long for the app behind it. Which timeout fired (nginx proxy_read_timeout,...
- 429 Too Many Requests429 means you hit a rate limit. How to read Retry-After, back off correctly with jitter, and find which...
- 500 Internal Server ErrorA 500 is the server's generic failure code, usually an unhandled exception. Where to find the real error...