HTTP
503 - Service Unavailable
Hitting a 503 Service Unavailable means the server is temporarily unable to handle requests—it's overloaded, under maintenance, or resources are exhausted. This server-side error (5xx) indicates a temporary condition that should resolve. Most common during traffic spikes that overwhelm the server, but also appears when maintenance mode is enabled, database connection pools are exhausted, or the server is scaling up to handle load.
#Common Causes
- →Frontend: Client can't fix 503s directly, but respecting Retry-After helps. Rapid retries worsen server load. No retry logic means users see errors during maintenance.
- →Backend: Server overloaded (CPU/memory exhausted). Database connection pool exhausted. Application in maintenance mode. Service dependencies unavailable (external APIs down). Rate limiting triggered at application level.
- →Infrastructure: Load balancer marks all backends as unhealthy. All upstream servers overloaded. Maintenance mode enabled in infrastructure. Auto-scaling hasn't caught up with traffic spike. CDN origin server overloaded.
✓Solutions
- 1Step 1: Diagnose - Check server logs for overload indicators (high CPU, memory usage). Review Retry-After header value. Check if maintenance mode is enabled. Review database connection pool metrics.
- 2Step 2: Diagnose - Check application monitoring for resource exhaustion. Review load balancer health check status. Check if all upstream servers are down. Examine traffic patterns (DDoS, traffic spike).
- 3Step 3: Fix - Client-side: Respect Retry-After header values. Implement exponential backoff for retries. Show user-friendly "Service temporarily unavailable" messages. Queue requests instead of rapid retries.
- 4Step 4: Fix - Server-side: Scale resources (add more instances, increase memory). Increase database connection pool size. Disable maintenance mode if not needed. Implement request queuing. Add circuit breakers for dependencies.
- 5Step 5: Fix - Infrastructure: Scale horizontally (add more backend servers). Configure auto-scaling rules. Review load balancer health check thresholds. Enable CDN caching to reduce origin load.
</>Code Examples
Fetch API: Respect Retry-After Header
1// Client-side: Handle 503 with Retry-After header
2async function fetchWithServiceRetry(url, options = {}, maxRetries = 5) {
3 for (let attempt = 0; attempt < maxRetries; attempt++) {
4 const response = await fetch(url, options);
5
6 if (response.status === 503) {
7 // Check Retry-After header (seconds) or use exponential backoff
8 const retryAfter = response.headers.get('Retry-After');
9 let delay;
10
11 if (retryAfter) {
12 // Parse Retry-After (can be seconds or HTTP-date)
13 const retryAfterNum = parseInt(retryAfter);
14 if (!isNaN(retryAfterNum)) {
15 delay = retryAfterNum * 1000; // Convert to milliseconds
16 } else {
17 // HTTP-date format
18 const retryDate = new Date(retryAfter);
19 delay = Math.max(0, retryDate.getTime() - Date.now());
20 }
21 } else {
22 // Exponential backoff with jitter
23 delay = Math.pow(2, attempt) * 1000 + Math.random() * 1000;
24 }
25
26 if (attempt < maxRetries - 1) {
27 console.log(`Service unavailable, retrying in ${Math.ceil(delay / 1000)}s (attempt ${attempt + 1})`);
28 await new Promise(resolve => setTimeout(resolve, delay));
29 continue;
30 } else {
31 throw new Error('Service unavailable after maximum retries');
32 }
33 }
34
35 return response;
36 }
37}
38
39// Usage with user feedback
40async function loadData() {
41 try {
42 const response = await fetchWithServiceRetry('/api/data');
43 return await response.json();
44 } catch (error) {
45 showUserMessage({
46 type: 'warning',
47 title: 'Service Temporarily Unavailable',
48 message: 'The service is temporarily unavailable. Please try again in a few moments.',
49 });
50 throw error;
51 }
52}Express.js: Maintenance Mode and Resource Limits
1// Server-side: Handle service unavailable scenarios
2const express = require('express');
3const app = express();
4
5let isMaintenanceMode = false;
6let requestCount = 0;
7const MAX_CONCURRENT_REQUESTS = 100;
8
9// Maintenance mode middleware
10app.use((req, res, next) => {
11 if (isMaintenanceMode) {
12 return res.status(503)
13 .set('Retry-After', '3600') // 1 hour
14 .json({
15 error: 'Service Unavailable',
16 message: 'Service is under maintenance',
17 retryAfter: 3600,
18 });
19 }
20 next();
21});
22
23// Request limit middleware
24app.use((req, res, next) => {
25 requestCount++;
26
27 if (requestCount > MAX_CONCURRENT_REQUESTS) {
28 requestCount--;
29 return res.status(503)
30 .set('Retry-After', '60') // 1 minute
31 .json({
32 error: 'Service Unavailable',
33 message: 'Server is overloaded. Please try again later.',
34 retryAfter: 60,
35 });
36 }
37
38 res.on('finish', () => {
39 requestCount--;
40 });
41
42 next();
43});
44
45// Database connection pool check
46app.use(async (req, res, next) => {
47 try {
48 // Check if database connection pool is available
49 const pool = db.getPool();
50 if (pool.totalCount >= pool.max) {
51 return res.status(503)
52 .set('Retry-After', '30')
53 .json({
54 error: 'Service Unavailable',
55 message: 'Database connection pool exhausted',
56 retryAfter: 30,
57 });
58 }
59 next();
60 } catch (error) {
61 return res.status(503)
62 .set('Retry-After', '60')
63 .json({
64 error: 'Service Unavailable',
65 message: 'Database connection failed',
66 retryAfter: 60,
67 });
68 }
69});
70
71// Health check endpoint (bypasses all middleware)
72app.get('/health', (req, res) => {
73 res.json({
74 status: 'ok',
75 maintenanceMode: isMaintenanceMode,
76 requestCount: requestCount,
77 timestamp: new Date().toISOString(),
78 });
79});
80
81// Toggle maintenance mode
82app.post('/admin/maintenance', (req, res) => {
83 isMaintenanceMode = req.body.enabled || false;
84 res.json({ maintenanceMode: isMaintenanceMode });
85});Nginx: Service Unavailable Handling
1# Nginx: Configure service unavailable responses
2upstream backend {
3 server backend1:3000;
4 server backend2:3000;
5 # Health checks will mark servers as down if they return 503
6}
7
8server {
9 listen 80;
10 server_name api.example.com;
11
12 location /api/ {
13 proxy_pass http://backend;
14 proxy_set_header Host $host;
15 proxy_set_header X-Real-IP $remote_addr;
16
17 # Timeouts
18 proxy_connect_timeout 10s;
19 proxy_send_timeout 30s;
20 proxy_read_timeout 30s;
21
22 # Handle 503 from upstream
23 proxy_next_upstream error timeout http_500 http_502 http_503;
24 proxy_next_upstream_tries 2;
25
26 # Custom 503 error page
27 error_page 503 /503.html;
28 }
29
30 # Custom 503 page
31 location = /503.html {
32 root /usr/share/nginx/html;
33 internal;
34 default_type text/html;
35 return 503 '<!DOCTYPE html><html><head><title>Service Unavailable</title></head><body><h1>503 Service Unavailable</h1><p>The service is temporarily unavailable. Please try again later.</p></body></html>';
36 add_header Retry-After 60 always;
37 }
38
39 # Maintenance mode (return 503 for all requests)
40 # if ($maintenance_mode = 1) {
41 # return 503 'Service under maintenance';
42 # add_header Retry-After 3600 always;
43 # }
44}↗Related Errors
Provider Information
This error code is specific to HTTP services. For more information, refer to the official HTTP documentation.