Underlying Causes and Fixes for the “Too Many Redirects” Error
The "Too Many Redirects" error — displayed in browsers as ERR_TOO_MANY_REDIRECTS and corresponding to an HTTP redirect loop — occurs when a web server and client enter a circular chain of redirects that never resolves to a final destination. The browser aborts the request after exceeding its redirect threshold (typically 20 hops in Chrome) and surfaces this error instead of loading the page.
This is not a vague network glitch. It is a deterministic failure caused by a specific misconfiguration in your server rules, SSL settings, CMS database values, CDN configuration, or cached redirect data. Every instance has a traceable root cause, and every root cause has a precise fix. This guide walks through all of them with the technical depth required to resolve the issue permanently — whether you are running a WordPress site, a custom application, or a raw server stack on a VPS Hosting environment.
What Actually Happens During a Redirect Loop
When a browser requests a URL, the server may respond with a 301 Moved Permanently, 302 Found, or 307 Temporary Redirect status code pointing to a new location. The browser follows that location header, makes another request, and expects a 200 OK response at some point in the chain.
A redirect loop forms when:
- URL A redirects to URL B, and URL B redirects back to URL A (two-hop loop)
- URL A redirects to URL B, which redirects to URL C, which redirects back to URL A (multi-hop loop)
- A single URL redirects to itself (self-referential loop)
Browsers do not loop indefinitely. Chrome and Firefox both terminate after approximately 20 redirects and display ERR_TOO_MANY_REDIRECTS. Safari shows "Safari Can't Open the Page." The underlying HTTP behavior is identical across all of them.
Root Causes and Precise Fixes
1. Misconfigured Redirect Rules in .htaccess or Nginx
The most technically common cause is conflicting or circular rewrite rules in the server configuration layer.
Apache .htaccess example of a broken loop:
RewriteEngine On
RewriteRule ^page$ /page [R=301,L]This rule redirects /page to /page — a self-referential loop. Similarly, two rules that redirect between /old-url and /new-url in opposite directions will cause the same failure.
How to diagnose:
Open your .htaccess file and trace every RewriteRule and Redirect directive manually. Look for any rule where the target pattern can match the source of another rule.
grep -n "Redirect|RewriteRule|RewriteCond" /var/www/html/.htaccessFor Nginx, the equivalent issue appears in server or location blocks:
# Broken example — loop between two location blocks
location /old {
return 301 /new;
}
location /new {
return 301 /old;
}Audit your Nginx configuration with:
nginx -T | grep -A3 "return 301|rewrite"Fix: Ensure every redirect rule has a unique, non-overlapping source and destination. Use the [L] flag in Apache to stop rule processing once a match is found. In Nginx, prefer return 301 over rewrite for clarity and to avoid unintended chaining.
2. HTTP to HTTPS Redirect Misconfiguration
This is the single most common cause on modern hosting environments, particularly after adding an SSL Certificate without updating the application-level configuration.
The failure pattern looks like this:
- The web server forces all HTTP traffic to HTTPS via
.htaccessor Nginx config - The application (e.g., WordPress) has its
siteurlorhomeoption set tohttp://in the database - The application then redirects HTTPS requests back to HTTP
- The loop is:
HTTP → HTTPS (server) → HTTP (app) → HTTPS (server) → ...
Correct Apache .htaccess HTTPS redirect:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]Correct Nginx HTTPS redirect:
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}Critical pitfall: If you are behind a load balancer or reverse proxy (including Cloudflare), the backend server may not see HTTPS directly. The proxy terminates SSL and forwards the request as HTTP to your origin. Your server then sees %{HTTPS} = off and redirects to HTTPS again — creating a loop.
The fix is to check the X-Forwarded-Proto header instead:
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} =http
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]3. Cloudflare and CDN SSL Mode Mismatch
If you are using Cloudflare or another CDN in front of your origin server, the SSL/TLS encryption mode must match your origin's actual certificate status.
| Cloudflare SSL Mode | What It Does | When It Causes a Loop |
|---|
| — | — | — |
|---|
| **Off** | No encryption between Cloudflare and origin | If origin forces HTTPS, loop occurs |
|---|
| **Flexible** | HTTPS to Cloudflare, HTTP to origin | If origin also forces HTTP→HTTPS, loop occurs |
|---|
| **Full** | HTTPS to Cloudflare, HTTPS to origin (unvalidated cert) | Rarely causes loops; may cause cert errors |
|---|
| **Full (Strict)** | HTTPS to Cloudflare, HTTPS to origin (valid cert required) | Correct setting for most production sites |
|---|
The most common Cloudflare loop scenario: SSL mode is set to Flexible, and the origin server has an .htaccess rule forcing HTTP to HTTPS. Cloudflare sends HTTP to the origin, the origin redirects to HTTPS, Cloudflare receives that redirect, sends HTTP again — infinite loop.
Fix: Set Cloudflare SSL mode to Full (Strict) and ensure your origin has a valid certificate. Alternatively, if you must use Flexible, remove the HTTP→HTTPS redirect from your origin server entirely and let Cloudflare handle it via a Page Rule or the "Always Use HTTPS" toggle.
Also disable Automatic HTTPS Rewrites in Cloudflare if your origin is already handling redirects — having both active doubles the redirect logic.
4. WordPress URL Settings Mismatch
WordPress stores its canonical URLs in two database fields: siteurl (the WordPress core installation URL) and home (the public-facing URL). When these values conflict with the server's redirect rules or with each other, a loop is almost inevitable.
Check current values via WP-CLI:
wp option get siteurl
wp option get homeOr query the database directly:
mysql -u dbuser -p dbname -e "SELECT option_name, option_value FROM wp_options WHERE option_name IN ('siteurl','home');"Both values must use the same protocol (https://) and the same domain format (with or without www) that your server configuration enforces.
Fix via WP-CLI:
wp option update siteurl 'https://example.com'
wp option update home 'https://example.com'Fix via wp-config.php (overrides database values, useful when locked out of admin):
define('WP_HOME', 'https://example.com');
define('WP_SITEURL', 'https://example.com');Plugin conflicts: Redirect manager plugins (Redirection, Simple 301 Redirects, Yoast SEO's redirect module) can create database-stored redirect rules that conflict with server-level rules. Temporarily rename the plugins directory to isolate the issue:
mv /var/www/html/wp-content/plugins /var/www/html/wp-content/plugins_disabledRe-enable plugins one at a time after confirming the loop is gone.
5. Browser Cache and Cached 301 Redirects
Browsers cache 301 Moved Permanently responses aggressively — by design. If a 301 redirect was previously served for a URL and then the redirect target was changed, the browser may still follow the old cached redirect, which can point to a now-looping destination.
This is a particularly deceptive scenario because the loop may not reproduce on a fresh browser or another device, leading administrators to incorrectly conclude the server is fine.
Diagnosis steps:
- Open the URL in an incognito/private window (no cached data)
- Test with
curlto bypass browser caching entirely:
curl -I -L --max-redirs 10 https://example.com- Use an online redirect chain tracer (e.g.,
redirect-checker.orgorhttpstatus.io) to see every hop server-side
Fix: Clear browser cache and cookies for the affected domain. In Chrome: Settings > Privacy and Security > Clear Browsing Data > select Cached Images and Files + Cookies.
For server-side caching (Varnish, Redis, OPcache, or a caching plugin like W3 Total Cache):
# Flush Varnish cache
varnishadm ban req.url ~ .
# Flush OPcache via PHP CLI
php -r "opcache_reset();"6. www vs. Non-www Redirect Conflicts
A frequently overlooked source of redirect loops is inconsistent handling of the www subdomain. If your server redirects www.example.com to example.com and simultaneously redirects example.com to www.example.com, you have a loop.
Check your current DNS and redirect configuration:
curl -sI http://www.example.com | grep -i location
curl -sI http://example.com | grep -i locationCorrect Apache configuration (canonical non-www):
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www.(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]Ensure this rule is not paired with another rule that redirects the non-www version back to www.
7. Corrupted or Conflicting Cookies
Some applications use cookies to manage redirect state (e.g., login redirects, locale detection, A/B testing frameworks). If a cookie stores a redirect target that itself triggers another redirect, the loop is driven by application logic rather than server configuration.
Diagnosis: Test the URL with all cookies cleared for that domain. In Chrome DevTools (F12), go to Application > Storage > Cookies, select the domain, and delete all entries. Reload the page.
If the error disappears after clearing cookies, the issue is in your application's session or redirect logic, not the server configuration.
Comparison: Common Redirect Loop Scenarios and Their Fixes
| Scenario | Visible Symptom | Primary Fix Location |
|---|
| — | — | — |
|---|
| `.htaccess` circular rule | Loop on all pages | `.htaccess` file |
|---|
| Cloudflare Flexible SSL + origin HTTPS redirect | Loop on all pages | Cloudflare SSL mode |
|---|
| WordPress `siteurl`/`home` HTTP vs HTTPS mismatch | Loop on all pages | Database or `wp-config.php` |
|---|
| Reverse proxy not forwarding `X-Forwarded-Proto` | Loop only on proxied traffic | Server config (`RewriteCond`) |
|---|
| Cached `301` in browser | Loop only on specific browser/device | Browser cache clear |
|---|
| Plugin-generated redirect conflict | Loop on specific URLs | Plugin deactivation |
|---|
| `www`/non-`www` bidirectional redirect | Loop on domain root | `.htaccess` or Nginx server block |
|---|
| Cookie-driven redirect loop | Loop only when logged in or after first visit | Application session logic |
|---|
Systematic Diagnosis Workflow
Before touching any configuration file, follow this sequence to isolate the cause:
Step 1 — Reproduce without cache:
curl -v -L --max-redirs 25 https://example.com 2>&1 | grep -E "Location:|< HTTP"This shows every redirect hop and the final response code. If you see the same URLs repeating, you have confirmed the loop and identified which URLs are involved.
Step 2 — Check server error logs:
# Apache
tail -100 /var/log/apache2/error.log | grep -i redirect
# Nginx
tail -100 /var/log/nginx/error.log | grep -i rewriteStep 3 — Isolate the layer:
- If the loop disappears when you comment out
.htaccessrules, the issue is in Apache configuration - If it disappears when you bypass Cloudflare (test via direct IP), the issue is in CDN settings
- If it disappears when you rename the plugins directory, the issue is in a WordPress plugin
- If it disappears in incognito but not normal mode, the issue is browser cache or cookies
Step 4 — Validate SSL certificate binding:
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | grep -E "subject|issuer|Verify"An invalid or mismatched certificate can cause HTTPS redirect failures that manifest as loops.
Preventing Redirect Loops in Production
Once resolved, these practices prevent recurrence:
- Use a single canonical redirect rule that handles both HTTP→HTTPS and www→non-www in one pass, not two separate rules that can interact
- Test redirect chains before deploying using
curl -Lor an online redirect checker after any configuration change - Set
301redirects only when permanent — use302during testing so browsers do not cache the redirect - Document every redirect rule in your
.htaccessor Nginx config with inline comments explaining the intent - Monitor with uptime tools that follow redirect chains and alert when hop count exceeds a threshold
For teams managing multiple sites on a VPS with cPanel, cPanel's Redirects module provides a visual interface for managing redirect rules, but it writes to .htaccess — always verify the output manually after using the GUI.
If you are running a high-traffic site or multiple domains, a Dedicated Server gives you full control over Nginx or Apache configuration at the system level, eliminating shared-environment constraints that can complicate redirect debugging.
For sites using VPS Control Panels like Plesk or DirectAdmin, redirect rules may be managed through the panel's interface as well as directly in configuration files — check both locations to ensure they are not contradicting each other.
Technical Key-Takeaway Checklist
Use this as a pre-flight checklist when diagnosing ERR_TOO_MANY_REDIRECTS:
- [ ] Run
curl -v -L --max-redirs 25to map the full redirect chain before touching any config - [ ] Confirm both
siteurlandhomein WordPress match the protocol and domain your server enforces - [ ] Verify Cloudflare SSL mode is Full (Strict) if your origin has a valid certificate
- [ ] Check that
.htaccessor Nginx config usesX-Forwarded-Protoinstead of%{HTTPS}when behind a proxy - [ ] Ensure
wwwand non-wwwredirects are unidirectional — one canonical form only - [ ] Temporarily disable all redirect-related plugins and re-enable one at a time
- [ ] Clear browser cache and test in incognito to rule out cached
301responses - [ ] Inspect application cookies for redirect state that may be driving a loop
- [ ] Validate SSL certificate is valid and correctly bound to the domain
- [ ] After fixing, use
302temporarily before switching to301to prevent re-caching a broken redirect
FAQ
What is the difference between ERR_TOO_MANY_REDIRECTS and a 310 HTTP status code?
ERR_TOO_MANY_REDIRECTS is a client-side browser error triggered after the browser exceeds its redirect follow limit (typically 20). HTTP 310 is a rarely used status code meaning "Too Many Redirects" at the protocol level. In practice, almost all redirect loop errors you encounter in production are the browser-side ERR_TOO_MANY_REDIRECTS — not a server-issued 310 response.
Why does the redirect loop only appear on some browsers or devices but not others?
The most common reason is a cached 301 redirect stored in the browser that points to a now-invalid destination. Because 301 responses are cached indefinitely by default, a browser that previously visited the URL may follow a stale redirect chain. Testing in incognito mode or on a fresh device bypasses this cache and reveals the server's current behavior.
How do I fix a redirect loop in WordPress when I cannot access the admin panel?
Add the following lines directly to wp-config.php to override the database URL values, then access the admin panel to correct the settings properly:
define('WP_HOME', 'https://example.com');
define('WP_SITEURL', 'https://example.com');Alternatively, update the values directly in the database using wp-cli or a direct MySQL query against the wp_options table.
Can a redirect loop affect SEO rankings?
Yes. A redirect loop returns no 200 OK response, meaning Googlebot cannot crawl or index the affected URL. If the loop affects your homepage or key landing pages, it will result in deindexing over time. Additionally, any 301 link equity passing through the looping URL is effectively lost. Resolving the loop promptly and verifying crawlability in Google Search Console is essential.
How do I prevent Cloudflare from causing redirect loops with my SSL setup?
Set Cloudflare's SSL/TLS encryption mode to Full (Strict) in the SSL/TLS dashboard. This ensures Cloudflare communicates with your origin over HTTPS using a validated certificate, eliminating the HTTP↔HTTPS loop that Flexible mode creates when the origin server also enforces HTTPS. Additionally, disable "Automatic HTTPS Rewrites" if your origin or .htaccess already handles the HTTP-to-HTTPS redirect to avoid double-redirect logic.
