How I Fix ERR_TOO_MANY_REDIRECTS on WordPress Sites — The Six Causes I See Over and Over
· 10 min read
A client messages me: "My site just shows an error — something about too many redirects." They send a screenshot of Chrome's ERR_TOO_MANY_REDIRECTS page. The site loaded fine yesterday. Nothing changed — or so they think.
This is one of the most common WordPress errors I deal with. The browser tries to load the page, gets bounced to another URL, which bounces it again, and again, until the browser gives up after about 20 hops. The site is technically online — it's just stuck in an infinite loop.
After fixing this on dozens of sites over the years, I've found it almost always comes down to one of six causes. Here's how I diagnose it and what I do for each one.
Start With curl, Not the Browser
The browser's error page tells you nothing about where the loop happens. The first thing I do is check the redirect chain from the command line:
curl -IL https://example.com 2>&1 | grep -E "^HTTP/|^location:"
This shows every hop in the chain. A healthy site returns one HTTP/2 200. A redirect loop looks like this:
HTTP/2 301
location: https://example.com/
HTTP/2 301
location: https://example.com/
HTTP/2 301
location: https://example.com/
That tells me the server keeps redirecting to itself. If I see it bouncing between http:// and https://, that's an SSL configuration issue. If it's bouncing between www and non-www, that's a URL mismatch. The pattern in the location: headers narrows the cause immediately.
I also check what happens when I request the HTTP version directly:
curl -IL http://example.com 2>&1 | grep -E "^HTTP/|^location:"
If HTTP redirects to HTTPS which redirects back to HTTP — that's the classic SSL redirect loop.
Cause 1: Cloudflare Flexible SSL
This is the single most common cause I see. A client adds Cloudflare to their WordPress site and their SSL/TLS encryption mode is set to Flexible. Here's what happens:
- A visitor requests
https://example.com - Cloudflare terminates the SSL and sends the request to the origin server over plain HTTP
- The origin server sees an HTTP request and redirects to HTTPS (because WordPress or nginx is configured to force HTTPS)
- The request goes back through Cloudflare, which again strips SSL and sends HTTP to the origin
- The origin redirects to HTTPS again — infinite loop
The fix is straightforward. In the Cloudflare dashboard, go to SSL/TLS and change the encryption mode from Flexible to Full or Full (Strict). Full (Strict) requires a valid SSL certificate on your origin server — if you're using Let's Encrypt or your host provides one, this is the correct setting.
If for some reason you can't install a certificate on the origin server and must use Flexible, add this to wp-config.php above the /* That's all, stop editing! */ line:
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$_SERVER['HTTPS'] = 'on';
}
This tells WordPress to trust Cloudflare's X-Forwarded-Proto header instead of checking the actual connection. But the better solution is always to use Full (Strict) with a real certificate.
Cause 2: WordPress URL Mismatch
WordPress stores two URLs in the database: siteurl (the WordPress installation address) and home (the address visitors use). If these don't match — one has https:// and the other has http://, or one has www. and the other doesn't — you get a redirect loop.
I check these with WP-CLI:
wp option get siteurl
wp option get home
If they don't match, I fix them:
wp option update siteurl 'https://example.com'
wp option update home 'https://example.com'
If WP-CLI isn't available or the site is completely unreachable, I override them in wp-config.php:
define('WP_HOME', 'https://example.com');
define('WP_SITEURL', 'https://example.com');
This happens most often after migrations, domain changes, or when someone toggles SSL on and only updates one of the two values.
Cause 3: Reverse Proxy or Load Balancer Without Proper Headers
This is the same underlying problem as Cloudflare Flexible SSL, but on custom infrastructure. The site sits behind nginx as a reverse proxy, a load balancer, or a service like AWS ALB. SSL terminates at the proxy layer, and the backend WordPress server receives plain HTTP.
WordPress checks $_SERVER['HTTPS'] to decide if the request is secure. Behind a proxy, that value is empty or off, even though the visitor's connection is encrypted. If anything in WordPress forces HTTPS — a plugin, a .htaccess rule, FORCE_SSL_ADMIN — it redirects to HTTPS, the proxy strips it, and the loop begins.
The fix depends on the proxy. For nginx reverse proxies, ensure you're passing the right header:
location / {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://backend;
}
Then in wp-config.php:
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$_SERVER['HTTPS'] = 'on';
$_SERVER['SERVER_PORT'] = 443;
}
For nginx with PHP-FPM (no reverse proxy — just FastCGI), the issue is slightly different. You need to pass the HTTPS parameter directly in your PHP location block:
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param HTTPS on;
}
The fastcgi_param HTTPS on; line must come after the include fastcgi_params; line, or the default value from fastcgi_params overrides it.
Cause 4: Duplicate HTTPS Redirects in .htaccess
On Apache servers, I often find multiple HTTPS redirect rules stacked on top of each other. WordPress plugins add their own, the hosting control panel adds one, and sometimes the site owner adds another from a tutorial they found online. The result is rules that conflict or create loops.
A typical problem looks like this in .htaccess:
# Added by a security plugin
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Added by the hosting panel
RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Behind a proxy, both conditions are always true (because the connection to Apache is HTTP on port 80), so the redirect fires on every request — even ones that are already HTTPS from the visitor's perspective.
I clean out all custom redirect rules and replace them with a single, proxy-aware rule:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
The second RewriteCond checks the X-Forwarded-Proto header, so the redirect only fires when the original visitor connection is genuinely not HTTPS.
Cause 5: Plugin Conflicts
Redirect plugins, SSL plugins, and security plugins are the usual suspects. I've seen Really Simple Security (formerly Really Simple SSL), Redirection, Yoast SEO, and various caching plugins all cause redirect loops through misconfigured rules.
The fastest way to test is to disable all plugins via WP-CLI:
wp plugin deactivate --all
If the redirect loop stops, reactivate plugins one at a time to find the culprit:
wp plugin activate plugin-name
If you can't access WP-CLI or SSH, rename the plugins folder via SFTP:
mv wp-content/plugins wp-content/plugins-disabled
WordPress will deactivate all plugins automatically when it can't find the folder. Test the site, then rename it back and use the admin dashboard to selectively reactivate.
The most common plugin-related loop I see is when a caching plugin serves a cached redirect response. Even after fixing the underlying cause, the old 301 redirect is still being served from cache. Purging the cache (and the browser cache) resolves it.
Cause 6: wp-admin Only Redirect Loop
Sometimes the public site loads fine but /wp-admin is stuck in a redirect loop — you log in, get bounced to wp-login.php, which bounces back to wp-admin, endlessly.
This is usually caused by FORCE_SSL_ADMIN being set to true in wp-config.php while the server doesn't properly report HTTPS. WordPress forces the admin to HTTPS, detects the connection as HTTP, and redirects again.
The fix is the same X-Forwarded-Proto snippet from Cause 3, placed above the FORCE_SSL_ADMIN definition in wp-config.php:
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$_SERVER['HTTPS'] = 'on';
}
define('FORCE_SSL_ADMIN', true);
The order matters. WordPress reads wp-config.php top to bottom, so the HTTPS server variable must be set before FORCE_SSL_ADMIN evaluates it.
Another cause of wp-admin loops is corrupted cookies. If the site domain changed or switched between www and non-www, the old login cookies point to the wrong domain. Clearing all cookies for the domain in the browser fixes it. You can also force WordPress to use specific cookie domains in wp-config.php:
define('COOKIE_DOMAIN', 'example.com');
define('ADMIN_COOKIE_PATH', '/');
My Diagnostic Checklist
When I get a redirect loop ticket, I run through this in order:
curl -ILon both HTTP and HTTPS to map the redirect chain- Check if Cloudflare or another CDN is in front of the site — inspect the
cf-rayorserverresponse header - Check the SSL/TLS encryption mode in the CDN dashboard
- Verify
siteurlandhomematch withwp option get - Look for
X-Forwarded-Protohandling inwp-config.php - Check
.htaccessfor duplicate or conflicting redirect rules - Disable plugins to isolate conflicts
- Clear all caches — server, plugin, CDN, and browser
Nine times out of ten, it's one of the first three items on that list.
Stop Firefighting. Start Maintaining.
Redirect loops are one of those problems that shouldn't happen if the server is configured correctly from the start. I manage 70+ WordPress sites for UK agencies and businesses, and part of what I do is make sure the SSL, proxy headers, and DNS are set up properly so issues like this never surface.
Whether you need ongoing maintenance, emergency support, or a one-off configuration fix — I can help.
