errors.x7.al › HTTP status codes

503 Service Unavailable

A 503 Service Unavailable is the HTTP status code a server returns when it is temporarily unable to handle a request, usually because it is overloaded or undergoing maintenance. The key word is temporary: unlike a 500, which says something broke, a 503 says the server is deliberately, and usually briefly, not serving traffic. Servers often pair it with a Retry-After response header telling clients how many seconds to wait before trying again.

Advertisement

What it means

The 503 code sits in the same 5xx family as 500 and 502, but its meaning is different. A 500 says the server tried and failed. A 502 says a proxy could not understand an upstream. A 503 says the server knows it cannot serve the request right now and is telling you so instead of attempting work it cannot finish. It is the honest “come back later” of HTTP, and it is expected to be transient.

This is why the Retry-After header matters. When a server sends Retry-After: 120, it is stating that service should resume in about two minutes. Well-behaved clients and search crawlers honour that value: they back off rather than hammering the server, which is exactly what you want during a spike. A 503 without a Retry-After is still valid but gives the client no guidance, so it may retry too aggressively and make the overload worse.

The code is also what good systems return on purpose. When an application detects that it is at capacity or that a dependency is down, returning a fast 503 with a retry hint is far healthier than accepting requests it will only time out or crash on. A controlled 503 protects the service; a runaway failure does not.

Common causes

  • A traffic spike or overwhelming request volume pushes the server past the capacity it can serve in time.
  • Planned maintenance, a deploy, or a data migration takes the service down deliberately, with the 503 as the intended response.
  • A resource is exhausted — CPU, memory, open connections, or application worker threads are all consumed.
  • An upstream dependency such as a database or cache is unavailable, so the application sheds load instead of serving broken pages.
  • A proxy or load balancer finds no healthy backends and returns 503 because the pool is empty.

How to fix it

  1. Confirm whether it is load or maintenance. Check the load average and current connections before assuming a fault.
    uptime
    ss -s
  2. Read the logs and any maintenance flag. A deploy in progress or a feature flag that disables serving explains the code immediately.
    journalctl -u myapp --since "15 min ago"
    tail -n 50 /var/log/nginx/error.log
  3. Add capacity when it is overload. Scale out to more instances or raise worker and connection limits, then confirm the pool is populated again.
    systemctl restart myapp
    ss -lntp | grep 3000
  4. Check dependencies. If the database or cache is down, restoring it usually ends the 503 at once.
    mysqladmin ping
    redis-cli ping
  5. Return a proper Retry-After. For planned downtime, send the estimated seconds so clients and crawlers back off instead of retrying in a tight loop.
Advertisement

How to prevent it

Capacity planning and autoscaling are the structural answer. Measure normal and peak request rates, provision headroom above the peak, and let autoscaling add instances when demand rises. Health checks that remove unhealthy backends keep a proxy from returning 503 for a pool that still contains working servers, and rate limiting or load shedding keeps one noisy client from consuming the capacity everyone shares.

For planned work, schedule maintenance in a window and announce it in advance. Serve a clear 503 with a Retry-After value during the window, and keep maintenance pages lightweight and static so they do not depend on the very components being worked on. Track your error rate and saturation signals with alerts, so you learn that the service is near its limit before it starts turning visitors away. Handled this way, a 503 stays rare, brief, and honest.

Advertisement