Your site won't come up and the browser shows a white page with the number 503. The first thing most site admins do is restart the web service. In half of cases this makes the problem worse, because 503 has two completely different meanings, and until you know which one you're looking at, any action is a shot in the dark.
Is the 503 error deliberate or unwanted?
One look at the response header makes this clear. If the server itself has decided to temporarily cut off the service, it sends the Retry-After header:
HTTP/1.1 503 Service Unavailable
Retry-After: 3600
Cache-Control: no-store
The presence of Retry-After means someone designed this 503 in advance. This happens in maintenance mode, in WordPress's maintenance mode, or when Nginx as a reverse proxy sits behind a shut-down upstream. If this header is absent and instead you see Server: nginx in the response with the default body, the upstream is probably really dead.
The practical difference between the two is in the log. A deliberate 503 is usually recorded in access.log with code 503 and no trace in error.log. An unwanted 503 always has a corresponding line in error.log:
connect() failed (111: Connection refused) while connecting to upstream
Or its PHP-FPM version:
connect() to unix:/run/php/php8.2-fpm.sock failed (2: No such file or directory)
I see this second line a lot. It means the PHP-FPM socket doesn't exist; either the service didn't come up, or the PHP version changed and the socket path in the Nginx config wasn't updated.
Why Google doesn't penalize a proper 503
Google's crawler distinguishes between 503 and 500, and this difference is critical for site ranking. 503 is a temporary code. Google waits, visits again, and doesn't remove the page from the index. But a 500 or 404 over several weeks can drop the page from search results.
The condition is that the 503 is genuinely temporary. If your site returns 503 for three weeks straight, Google sees it as a permanent failure and organic traffic drops. My personal experience: sites that stayed in maintenance mode for a week after a server migration felt a 30 to 40 percent traffic drop two to three weeks later.
A technical point that's rarely mentioned: in maintenance mode, be sure to set the Retry-After header. A reasonable value is between 3600 and 86400 seconds. Without this header, the crawler tries at short, back-to-back intervals and puts extra load on the very server that's under maintenance.
Quick diagnosis in three minutes
Before any change, go through this order:
- Check the headers with
curl -I https://example.com. A 503 withRetry-Aftermeans deliberate. - On the server, run
systemctl status nginx php8.2-fpm. If one of the services isfailed, that's the problem. - With
tail -f /var/log/nginx/error.logalongside a request, read the error line. - With
ss -lntp | grep :80, see whether anyone is listening on port 80.
If the services are healthy and you still get 503, it's probably a resource limit. When PHP-FPM hits the pm.max_children ceiling, new requests queue up and return 503 after timeout. You recognize this state in /var/log/php8.2-fpm.log with the following message:
WARNING: [pool www] server reached pm.max_children setting (10), consider raising it
Raising this number isn't the solution, it just moves the symptoms around. Each PHP-FPM process takes about 30 to 80 megabytes of RAM. If you take the number from 10 to 40 on a 2-gigabyte server, instead of 503 you'll get OOM Killer errors and MySQL restarts. First measure actual memory usage with free -m, then decide.
Where they go wrong
The most common mistake I've seen: the site admin solves the 503 by restarting Nginx, the site comes up for two minutes, then falls again. The reason is that the problem was in another layer. If the database is running a heavy query or the disk has hit its IOPS ceiling, restarting the web server only empties the request queue.
The sign is this: after each restart, the site works for exactly a few minutes and then the same 503 returns. In this case, instead of the web server, go to SHOW FULL PROCESSLIST; in MySQL and iostat -x 1. If disk %util is above 90 percent, the bottleneck is I/O, not the web server.
Mistake number two: putting the 503 page on a static file without the correct status code. Some people return the maintenance page with a 200 code. This is the worst thing possible for SEO, because Google indexes the "site is under maintenance" content as the page's real content.
Implement a deliberate 503 correctly
In Nginx, the simplest way is to use a static file with the correct code:
location / {
if (-f /var/www/maintenance.flag) {
return 503;
}
}
error_page 503 /maintenance.html;
location = /maintenance.html {
internal;
}
With this setting, you just need to create or delete the maintenance.flag file; no reload is needed. To let Google know it's temporary too, add the Retry-After header in the error_page block.
If the site is on WordPress, maintenance mode plugins do the same thing, but some of them return a 200 code. Before activating, check with curl -I that you're really getting a 503.
When to go for infrastructure upgrade
If after correctly setting pm.max_children, optimizing queries, and enabling caching, you still get 503 during peak traffic hours, the problem is capacity, not settings. At this point you have two paths: separating the database onto another server, or migrating to a dedicated server with dedicated resources.
My choice in most cases is the first path, because it's cheaper and answers faster. But if your traffic consistently exceeds one server's capacity and disk I/O is the main bottleneck, separating the database only adds complexity and you should go for stronger hardware. For small and medium sites whose problem is PHP-FPM settings and caching, a Linux host with sufficient resources and the ability to fine-tune PHP-FPM is enough.
Before any migration, document the current state. With free webmaster tools you can measure server response time and DNS status, and compare after migration. If you're unsure whether the problem is DNS or the server, DNS and network lookup is the fastest way to separate the two.
A note about caching: if your site is behind a CDN, a 503 from the origin may get cached at the edge and continue for a few minutes even after the problem is fixed. In this case you need to purge the cache. The guide on browser caching and Cache-Control headers explains how to set headers so that error responses aren't cached.
Frequently asked questions
Is a 503 error dangerous for SEO?
A 503 error isn't dangerous for SEO by itself, because it's a temporary status code and Google doesn't remove the page from the index. The danger starts when the 503 drags on. If it continues for more than two to three weeks, Google sees it as a permanent failure and the site's ranking drops.
To be safe, always send the Retry-After header in the 503 response and make sure the maintenance page isn't returned with a 200 code.
How do I tell whether the 503 is from my own server or the CDN?
With curl -I --resolve example.com:443:origin-server-IP https://example.com, hit the origin directly. If the response is 200 but you get 503 through the domain, the problem is in the CDN layer.
In this case, look at the Server and CF-Ray or similar headers in the response. If it shows the CDN provider's name, you should look for the error in the CDN panel, not on your own server.
Does restarting Nginx fix the 503 error?
Only if the real cause is stuck Nginx processes or a full request queue. In most cases the 503 comes from PHP-FPM, the database, or disk I/O, and restarting Nginx only buys a few minutes.
Before restarting, always read error.log. If you see the connect() failed error, the problem is the upstream, not Nginx itself.
What's the difference between 503 and 502?
502 means the server as a gateway received an invalid response from the upstream, while 503 means the service is currently unavailable. In practice both usually come from the same root: an upstream that's down or overloaded.
Telling them apart from the log matters. 502 happens more when the upstream process dies mid-response; 503 when it can't connect at all or announces itself as unavailable.
Next time you see a 503, before any command, ask with curl -I whether it's deliberate or not. The answer to this one question cuts your troubleshooting path in half.
Comments 0
No comments yet — be the first!