What is happening
Two rules disagree. One says this URL belongs at B, the other says B belongs at A, and the browser bounces between them until it stops. Nothing is broken in the sense of being damaged: both rules are working exactly as configured, and the configuration is contradictory.
So do not start by disabling things. Start by reading the chain, because it names both ends of the loop and that is usually enough to identify the cause outright.
Trace the chain first
# follow every redirect and show only the status and destination
curl -sIL https://example.com/ | grep -Ei "^(HTTP/|location:)"
# the same without following, to see the very first hop
curl -sI https://example.com/ | grep -Ei "^(HTTP/|location:)"
# and the http version, which often behaves differently
curl -sIL http://example.com/ | grep -Ei "^(HTTP/|location:)"
Read the output as a list of hops. What it tells you:
| The chain shows | Almost certainly |
|---|---|
http to https to http repeating | An SSL proxy issue. WordPress does not know the request was secure |
example.com to www.example.com and back | WordPress Address and Site Address disagree, or a server rule fights them |
| A trailing slash appearing and disappearing | Two rules normalising the slash in opposite directions |
| One URL pointing at itself | A redirect plugin rule whose source and target are the same |
Only wp-login.php loops | Cookies or a cached redirect. See the login section |
One minute of this replaces an afternoon of disabling plugins.
The four causes
1. The two URL settings disagree
WordPress stores a WordPress Address (siteurl) and a Site Address (home). If one has www and the other does not, or one is http and the other https, you get a loop. You often cannot log in to fix it, which is the frustrating part, so set them outside the database.
# with WP-CLI
wp option get siteurl
wp option get home
wp option update siteurl 'https://example.com'
wp option update home 'https://example.com'
With no CLI, define them in wp-config.php, above the line that says to stop editing. These override the database and take effect at once, which makes them the right tool when you are locked out.
define( 'WP_HOME', 'https://example.com' );
define( 'WP_SITEURL', 'https://example.com' );
Pick one canonical form, with or without www, and make every layer agree: these two settings, your .htaccess or server config, your CDN, and any redirect plugin. The loop is a disagreement, so the fix is agreement.
Leave those defines in place while you sort the rest out, then decide whether to keep them. They are useful protection against a future accidental change, with the trade that the admin fields become read-only.
2. Two layers both forcing https
Count how many places are redirecting to https. It is often more than you think: an .htaccess rule, an SSL plugin, the host panel's force-https toggle, and the CDN. Any two of them can disagree about what the request already was.
Pick one and turn the rest off. Usually the best choice is the outermost layer, your host or CDN, because the redirect then happens before the request reaches PHP at all.
3. A redirect plugin rule pointing at itself
Easy to create accidentally, especially with wildcards. If you have a redirect plugin, look for a rule whose source matches its own target, or a wildcard broad enough to catch the destination.
wp plugin list --status=active --fields=name | grep -iE "redirect|ssl|https|cache"
Disable that single plugin, confirm the loop stops, then fix the rule rather than leaving the plugin off.
4. A cached redirect
Not a cause so much as the reason your fix appears not to work. Redirects get cached by page caches, CDNs and browsers, and a 301 in particular is cached aggressively by browsers.
After any change: clear the page cache, purge the CDN, and test in a private window. If it works in private browsing and not in your normal one, the remaining loop is in your own browser cache.
The SSL proxy loop, explained properly
This is the most common version on modern hosting and the one that looks inexplicable.
Your visitor connects over https to a load balancer, CDN or host proxy. That layer terminates SSL and forwards the request internally over plain http. WordPress looks at the request, sees http, and a force-https rule redirects to https. The visitor arrives back at the proxy, which forwards it as http again. Round it goes.
The fix is to tell WordPress to trust the header the proxy sets. Add this to wp-config.php, above the stop-editing line and before anything that uses the site URL.
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' ) {
$_SERVER['HTTPS'] = 'on';
}
Two cautions, because this snippet is pasted far more often than it is understood. Only trust that header when your site genuinely sits behind a proxy that sets it, since a header can be spoofed by a client if nothing upstream overwrites it. And check your host's documentation, because some use a different header name such as HTTP_CF_VISITOR, in which case this exact snippet does nothing.
When only the login page loops
A loop confined to wp-login.php or the admin usually has a different cause from a site-wide one. Work through these in order; the first is free and fixes a surprising share.
- Clear cookies for the domain and try again in a private window.
- Check www consistency. Logging in at one form and being redirected to the other invalidates the cookie.
- Exclude the admin from page caching. A cached redirect served to a logged-in user loops reliably.
- Check a custom cookie domain. If
COOKIE_DOMAINis defined inwp-config.phpand does not match the domain you are using, remove it. - Disable security plugins that relocate or protect the login URL.
# look for cookie or login constants that no longer match reality
grep -nE "COOKIE_DOMAIN|ADMIN_COOKIE_PATH|WP_HOME|WP_SITEURL|FORCE_SSL" wp-config.php
Working order
- Trace the chain with
curl -sILand write down both ends of the loop - Check
siteurlandhomeagree, and match the form you want - Count the layers forcing https and reduce it to one
- If the chain alternates http and https, apply the proxy fix
- Disable any redirect plugin to confirm, then fix its rule
- Clear every cache, including the CDN, and test in a private window
- For a login-only loop, clear cookies and check cookie constants
Step one is the one people skip, and it is the one that tells you the answer. Everything after it is confirmation.
If the chain is coming from a layer you cannot see, which is common with managed hosting and a CDN in front, that is the point to get help. Send us the URL and the output of the curl command above and we will tell you which layer is doing it.