14+ years building on WordPress / Replies in under 5 hours
Troubleshooting 9 min read · Updated July 2026

Resolving ERR_TOO_MANY_REDIRECTS in WordPress: A Step-by-Step Server & Database Guide

Photo of Ajay Khandal
Ajay Khandal
WordPress Developer
Resolving ERR_TOO_MANY_REDIRECTS in WordPress: A Step-by-Step Server & Database Guide
TL;DR

Redirect loops usually come from one of five places: <code>WP_HOME</code>/<code>WP_SITEURL</code> constants in <code>wp-config.php</code> set to the wrong protocol, mismatched <code>siteurl</code>/<code>home</code> values in the database, Cloudflare Flexible SSL conflicting with a WordPress HTTPS config, a broken <code>.htaccess</code> redirect rule, or a plugin clash. Run <code>curl -I -L yourdomain.com</code> first to identify which hop is looping, then fix the matching layer. WP-CLI (<code>wp option update siteurl</code>) is faster than phpMyAdmin for database fixes.

The ERR_TOO_MANY_REDIRECTS error appears when your browser gets caught in a loop: server sends it to URL B, URL B sends it back to URL A, and the cycle repeats until the browser gives up. WordPress sites hit this most often after an HTTP-to-HTTPS migration, a domain change, or adding a caching or security plugin — any of which can leave the site’s URL settings pointing in conflicting directions.

The six causes, in rough order of frequency: mismatched URL constants in wp-config.php, wrong siteurl/home values in the database, a broken .htaccess rule, Cloudflare or CDN SSL mode mismatch, a conflicting plugin, or a server-level Nginx/Apache redirect conflict. This guide works through all of them systematically.

Before You Touch Anything: Trace the Redirect Chain

Before editing files, find out which hop is looping. Open DevTools (F12) → Network tab → load your URL and look for the chain of 301/302 rows. Alternatively, run this from your terminal:

# Trace the full redirect chain from the command line.
# Shows each hop, HTTP status code, and Location header.
curl -I -L --max-redirs 10 https://yourdomain.com

# Typical output for a working HTTPS redirect (good):
# HTTP/1.1 301 Moved Permanently
# Location: https://yourdomain.com/
# HTTP/2 200

# Typical output for a loop (broken):
# HTTP/1.1 301 → Location: https://yourdomain.com/
# HTTP/1.1 301 → Location: http://yourdomain.com/
# HTTP/1.1 301 → Location: https://yourdomain.com/
# ... (repeats until curl gives up)

The output tells you immediately whether the loop is HTTP ↔ HTTPS (SSL misconfiguration), www ↔ non-www (DNS/WP URL setting), or something else entirely. That information determines which step below to start with — you rarely need all six.

Step 1: Clear Browser Cache and Cookies

Start here. Old redirect rules cached in the browser can produce the error even after the underlying issue is fixed. Clear cache and cookies, then try an Incognito/Private window or a different browser. If the error disappears, the site was already working — stale browser state was the only problem.

If the error persists in a clean browser session, continue to the file and database fixes below.

Step 2: Check wp-config.php for Hardcoded URLs

When WP_HOME and WP_SITEURL are defined in wp-config.php, they override the database values completely. If those constants have the wrong protocol or domain, every page load will redirect based on them regardless of what phpMyAdmin shows.

// If these constants are present in wp-config.php and wrong, they override everything.
// Temporarily comment them out to let WordPress fall back to database values.

// define( 'WP_HOME', 'http://yourdomain.com' );    // <-- comment out
// define( 'WP_SITEURL', 'http://yourdomain.com' ); // <-- comment out

// Or correct them to match your actual live URL:
define( 'WP_HOME', 'https://yourdomain.com' );
define( 'WP_SITEURL', 'https://yourdomain.com' );

// FORCE_SSL_ADMIN forces the wp-admin dashboard to HTTPS.
// If the front-end is not also on HTTPS, this can cause a loop.
// Only keep it if your entire site is served over HTTPS.
define( 'FORCE_SSL_ADMIN', true );

Note the FORCE_SSL_ADMIN constant at the bottom. This forces the wp-admin dashboard to HTTPS but does not force the front-end. If the front-end is not also served over HTTPS, having this constant alongside an HTTP WP_HOME creates a loop on the admin login page. Either remove it or ensure the entire site is on HTTPS before using it.

Step 3: Fix URL Settings in the Database

The siteurl and home rows in wp_options are the canonical source of WordPress’s URL. If they contain the wrong protocol or domain, every request redirects based on them. Both must be identical and must match your actual live URL exactly (including https:// if SSL is active, and consistent www vs. non-www).

Via WP-CLI (fastest for developer environments):

# Check current values stored in the database.
wp option get siteurl
wp option get home

# Fix them if wrong (replace with your actual domain):
wp option update siteurl 'https://yourdomain.com'
wp option update home 'https://yourdomain.com'

# If you migrated from HTTP to HTTPS and have serialized data issues,
# use search-replace to update all stored URLs at once.
# --skip-columns=guid leaves post GUIDs untouched (correct behaviour).
wp search-replace 'http://yourdomain.com' 'https://yourdomain.com' --skip-columns=guid --dry-run
# Remove --dry-run once you have verified the output.

Via phpMyAdmin (if WP-CLI is not available): Log into cPanel → phpMyAdmin → select your WordPress database → open wp_options (your prefix may differ, e.g. wp_xyz_options) → find the siteurl and home rows → double-click each option_value field and correct the URL. Save and clear your browser cache before testing.

If you can’t access either tool because the site is completely down, add the WP_HOME and WP_SITEURL defines (from Step 2) to wp-config.php as a temporary override to regain access, then correct the database values, then remove the hardcoded constants. Related database troubleshooting — including the Error Establishing a Database Connection error — is covered in the database connection error fix guide.

Step 4: Reset the .htaccess File

A malformed .htaccess rule is the second most common cause. Connect via FTP/SFTP, rename .htaccess to .htaccess_bak, and create a new file with only the default WordPress block:

# Rename your existing .htaccess to .htaccess_bak, then create a fresh one
# with only the default WordPress rewrite block:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

# After saving, go to Settings > Permalinks in wp-admin and click Save Changes
# to regenerate the full htaccess including any permalink structure rules.

If you need to force HTTPS at the Apache level (common on shared hosting), add the rewrite rule above the WordPress block — but only do this if you are not also using Cloudflare Flexible SSL, as that combination is one of the most reliable ways to create the exact loop you are trying to fix:

# If you want to force HTTPS at the server level, add this ABOVE the WordPress block.
# This is the correct single-redirect approach for Apache + SSL.

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>

# Do NOT also force HTTPS inside WordPress (WP_HOME/WP_SITEURL already https://)
# and do NOT use Cloudflare Flexible SSL alongside this rule — that combination
# creates the classic HTTP <-> HTTPS loop.

Step 5: Fix SSL and CDN (Cloudflare) Conflicts

This is the most frequently missed cause on modern WordPress sites. Cloudflare’s Flexible SSL mode decrypts traffic between Cloudflare and your browser using HTTPS, but sends it to your origin server as plain HTTP. If WordPress’s WP_HOME and WP_SITEURL are set to https://, your origin server receives an HTTP request and issues a 301 to HTTPS. Cloudflare receives the 301, sends an HTTPS request back to your origin — which arrives as HTTP again. That is the loop.

Fix: In your Cloudflare dashboard → SSL/TLS → Overview, set the encryption mode to Full or Full (strict). Full strict is correct when your origin server has a valid SSL certificate (including Cloudflare Origin Certificates); Full works when the certificate is self-signed or expired. Never use Flexible if WordPress is configured to use HTTPS.

If you are not on Cloudflare, check any other CDN or reverse proxy for similar “mixed SSL” settings. The symptom is always the same: the loop is HTTP → HTTPS → HTTP and the server logs show your own IP repeatedly requesting the same URL.

Step 6: Deactivate All Plugins

Security, caching, redirection, and SSL plugins (Really Simple SSL, Redirection, WP Rocket, Wordfence, Yoast) can all introduce redirect rules that conflict with each other or with server-level settings. If you cannot access wp-admin to deactivate them, do it via FTP:

  1. Connect via FTP/SFTP → navigate to /wp-content/.
  2. Rename the plugins folder to plugins_disabled.
  3. Clear your browser cache and try loading your site.
  4. If the site loads, rename plugins_disabled back to plugins.
  5. Log into wp-admin (plugins will show as inactive) and reactivate them one at a time, testing after each one. The loop returns when you activate the conflicting plugin.

For a faster isolation method, see the guide on identifying and fixing WordPress plugin conflicts. Once you’ve found the plugin, check its settings for an SSL or redirect option before deleting it — a single toggle often resolves the conflict without losing the plugin’s other functionality. Keeping plugins minimal and up to date also reduces exposure to this class of problem; the WordPress security practices guide covers plugin hygiene in detail.

Step 7: Check Server Configuration (Nginx and Apache)

If none of the above resolves the loop, the redirect is coming from the web server itself. For Apache servers on shared hosting, check your hosting control panel for redirect rules outside .htaccess (some hosts have a “Redirects” manager in cPanel that writes rules at the vhost level). For Nginx servers (VPS or dedicated), there is no .htaccess — all rewrites live in the server block configuration:

# Correct Nginx WordPress server block — the try_files directive handles rewrites.
# There is no Redirect or rewrite to index.php that could create a loop.

server {
    listen 443 ssl;
    server_name yourdomain.com www.yourdomain.com;

    root /var/www/html;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

# Redirect HTTP to HTTPS — one server block, not nested rewrites.
server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    return 301 https://$host$request_uri;
}

A common Nginx mistake is having a return 301 https://... inside a server { listen 443 } block, which redirects to itself on every HTTPS request. The HTTP-to-HTTPS redirect must live in a separate server { listen 80 } block, as shown above. If you do not have SSH access to edit Nginx config, contact your hosting provider with the curl -I -L output from Step 0 — it shows them exactly where the loop originates.

If you’re seeing a completely blank page or connection refused rather than the redirect error, that’s a different failure mode — the ‘This Site Can’t Be Reached’ error guide covers that scenario.

Summary: Which Step to Start With

  • HTTP ↔ HTTPS loop: Cloudflare SSL mode (Step 5) or WP_HOME/WP_SITEURL mismatch (Steps 2–3).
  • Loop after migrating domains: Database URL values (Step 3) — run wp search-replace to catch serialized data.
  • Loop appeared after installing a plugin: Plugin deactivation (Step 6).
  • Loop on a VPS/dedicated server: Nginx config (Step 7).
  • Works in one browser but not another: Browser cache (Step 1).

Frequently asked questions

The five most common causes are: (1) WP_HOME or WP_SITEURL constants in wp-config.php set to the wrong protocol or domain; (2) siteurl and home values in wp_options mismatched or pointing to the wrong URL; (3) Cloudflare or another CDN set to Flexible SSL while WordPress is configured for HTTPS; (4) a broken .htaccess redirect rule causing a loop; (5) a caching, security, or SSL plugin with conflicting redirect settings. Running curl -I -L yourdomain.com shows exactly which hop is looping.

The Cloudflare Flexible SSL mode is the most common cause of HTTP ↔ HTTPS redirect loops. In Flexible mode, Cloudflare sends HTTPS to visitors but plain HTTP to your origin server. If WordPress is configured for HTTPS (WP_HOME and WP_SITEURL both https://), your origin server redirects every HTTP request back to HTTPS — which Cloudflare receives and passes back as HTTP again, creating the loop. Fix it in your Cloudflare dashboard: SSL/TLS → Overview → set mode to Full (for self-signed certs) or Full (strict) (for valid/Cloudflare origin certs). Never use Flexible on a WordPress site configured for HTTPS.

Yes — WP-CLI is faster and safer for developers: wp option update siteurl 'https://yourdomain.com' and wp option update home 'https://yourdomain.com'. If you migrated from HTTP to HTTPS and have serialized data in the database, also run wp search-replace 'http://yourdomain.com' 'https://yourdomain.com' --skip-columns=guid --dry-run (drop --dry-run once the output looks correct). If neither phpMyAdmin nor WP-CLI is accessible, temporarily add define('WP_HOME', 'https://yourdomain.com') and define('WP_SITEURL', 'https://yourdomain.com') to wp-config.php to restore access, then fix the database values and remove the constants.

Via FTP/SFTP, rename the existing .htaccess file to .htaccess_bak (preserves it without activating it), then create a new .htaccess containing only the default WordPress rewrite block: RewriteEngine On, RewriteBase /, RewriteRule ^index.php$ - [L], RewriteCond %{REQUEST_FILENAME} !-f, RewriteCond %{REQUEST_FILENAME} !-d, RewriteRule . /index.php [L]. After the site loads, go to Settings → Permalinks in wp-admin and click Save Changes to regenerate the full file with your permalink structure.

After adding SSL, the loop usually comes from three places: (1) WP_HOME and WP_SITEURL still set to http:// while the server is forcing HTTPS; (2) Cloudflare Flexible SSL mode (see above); (3) both an .htaccess HTTPS-force rule and a WordPress URL setting both issuing a redirect to the same HTTPS URL, which can create double-redirect chains. The cleanest post-SSL setup is: WP_HOME/WP_SITEURL set to https:// in the database (or wp-config.php), a server-level HTTP→HTTPS redirect in .htaccess or the Nginx server block, and Cloudflare set to Full/Full (strict). No plugin-level SSL forcing needed.

If the loop persists after renaming the plugins folder, the cause is in one of the other layers: wp-config.php URL constants (Step 2), the database siteurl/home values (Step 3), .htaccess rules (Step 4), CDN/Cloudflare SSL mode (Step 5), or a server-level redirect rule outside WordPress entirely. Check the active theme's functions.php for any wp_redirect() calls that might be looping, and switch to a default theme (Twenty Twenty-Four) to rule out theme-level redirects. If the loop still exists with the default theme and no plugins, the issue is at the server or CDN layer and your hosting provider's server logs will identify it.

Photo of Ajay Khandal

Written by Ajay Khandal

I'm a freelance WordPress developer with 14+ years of experience building, fixing, and speeding up sites for businesses, agencies, and store owners across the US, UK, Europe, and Australia. I specialize in custom themes, WooCommerce, and performance — the kind of work that shows up as faster load times and fewer support tickets. No account managers, no outsourced tickets — you work directly with me, with replies typically inside 5 hours.

Work with me →