Fix HAProxy '503 Service Unavailable' Backend Down
The Error: "503 Service Unavailable"
Users hit your application and see:
HTTP/1.1 503 Service Unavailable
<html><body><h1>503 Service Unavailable</h1>
No server is available to handle this request.
</body></html>
HAProxy is running, the frontend is accepting connections, but every backend server is marked as down.
Root Cause
HAProxy returns 503 when no backend servers are available to handle a request. This means all servers in the backend have either:
- Failed health checks and are marked DOWN
- Reached their
maxconnlimit and are refusing new connections - Been put into maintenance mode (MAINT or DRAIN state)
- Never been reachable due to wrong IP, port, or network configuration
Step-by-Step Fix
1. Check Backend Server Status
Use the HAProxy stats socket or stats page:
# Via stats socket
echo "show stat" | sudo socat stdio /var/run/haproxy/admin.sock | \
awk -F',' '{print $1,$2,$18,$19}' | column -t
Or via the stats URL (if enabled): http://haproxy-host:8404/stats
Look for the status column. Healthy servers show UP. Problem servers show DOWN, MAINT, or NOLB.
2. Test Backend Server Connectivity
From the HAProxy server, manually test each backend:
# Test HTTP health check endpoint
curl -v http://backend-server:8080/health
# Test TCP connectivity
nc -zv backend-server 8080
# Check if the port is listening on the backend
ssh backend-server 'ss -tlnp | grep 8080'
3. Check HAProxy Logs
# Recent logs
sudo journalctl -u haproxy --since "10 minutes ago" --no-pager
# Look for health check failures
sudo journalctl -u haproxy | grep -i "DOWN" | tail -20
You'll see messages like:
Server mybackend/server1 is DOWN, reason: Layer4 connection problem, info: "Connection refused"
Server mybackend/server2 is DOWN, reason: Layer7 wrong status, info: "HTTP status 500"
4. Fix Health Check Configuration
If the health check path returns a non-2xx status, HAProxy marks the server as down. Update your config:
backend myapp
option httpchk GET /health
http-check expect status 200
server app1 10.0.1.10:8080 check inter 5s fall 3 rise 2
server app2 10.0.1.11:8080 check inter 5s fall 3 rise 2
Key parameters:
inter 5s-- check every 5 secondsfall 3-- mark DOWN after 3 consecutive failuresrise 2-- mark UP after 2 consecutive successes
If your app uses a different health endpoint or returns 204:
option httpchk GET /api/status
http-check expect status 200-299
5. Fix Connection Limits
If servers are up but overloaded:
echo "show stat" | sudo socat stdio /var/run/haproxy/admin.sock | \
awk -F',' '{print $1,$2,$5,$6,$7}' | column -t
Check if scur (current sessions) equals slim (session limit). If so, increase the limit:
backend myapp
server app1 10.0.1.10:8080 check maxconn 500
server app2 10.0.1.11:8080 check maxconn 500
6. Force a Server Back Up
If you've fixed the underlying issue and want to force HAProxy to re-check:
# Via stats socket
echo "set server mybackend/app1 state ready" | \
sudo socat stdio /var/run/haproxy/admin.sock
# Enable a server that was in maintenance
echo "set server mybackend/app1 state enabled" | \
sudo socat stdio /var/run/haproxy/admin.sock
7. Reload HAProxy
After config changes:
# Graceful reload (no dropped connections)
sudo systemctl reload haproxy
# Verify config syntax first
sudo haproxy -c -f /etc/haproxy/haproxy.cfg
8. Verify the Fix
# Check all backends are UP
echo "show stat" | sudo socat stdio /var/run/haproxy/admin.sock | \
grep -E "^myapp" | awk -F',' '{print $2, $18}'
# Test from a client
curl -I http://your-site.com
# Should return HTTP/1.1 200 OK
Prevention Tips
- Use multiple backend servers. A single backend means any failure causes a 503.
- Set reasonable
fallvalues.fall 3means 3 failures before marking down -- this prevents flapping on a single slow response. - Configure a maintenance page using
errorfile 503 /etc/haproxy/errors/503.httpso users see a helpful message instead of a bare 503. - Monitor backend health via the stats page or export metrics to Prometheus with
haproxy_exporter. - Use connection queuing (
timeout queue 30s) to queue requests during brief backend unavailability instead of immediately returning 503.
Was this article helpful?
SRE & Observability Engineer
If it's not measured, it doesn't exist. SLO-driven, metrics-obsessed, and the person who gets paged at 3 AM so you don't have to. Observability isn't optional.
Related Articles
HAProxy Load Balancing: From Installation to Production
Configure HAProxy for HTTP and TCP load balancing — installation, frontends, backends, health checks, ACLs, SSL termination, and the stats dashboard.
HAProxy Stick Tables For Session Persistence And DDoS Rate Limiting
If you've been running HAProxy in production for any length of time, you've probably hit one of two problems: either your users keep losing their sessions...
HAProxy ACL-Based Routing For Blue-Green Deployments Without Downtime
Blue-green deployments are one of the cleanest ways to ship without waking anyone up at 3am. HAProxy makes this surprisingly straightforward with ACL-based...
HAProxy Health Checks and Automatic Failover
Configure HAProxy health checks at TCP, HTTP, and application layers with automatic failover, backup servers, and alerting for production reliability.
HAProxy SSL Termination: Offload TLS Without the Headache
Configure HAProxy SSL termination to offload TLS from backend servers, including certificate management, hardening, and SNI-based routing.
Istio Gateway Returns 503 Service Unavailable: Debugging VirtualService And DestinationRule Misconfigurations
Nothing ruins your day quite like a 503 Service Unavailable error when you've spent hours configuring your shiny new Istio service mesh. I've been there mo...