Fix the WordPress login redirect loop

A WordPress login redirect loop throws you back to wp-login.php after you submit valid credentials. This article walks through the real causes in order of likelihood, shows you how to verify each one, and gives you a targeted fix per case.

This is the symptom-specific fixer. If you want the full explanation of why WordPress login redirect loops form in the first place, read WordPress login redirect loop: why it happens first. That article explains the cookie round-trip mechanism and what every fix on this page is actually targeting. The article you are reading now assumes you already recognise the symptom and want the steps.

What the loop looks like

You submit your username and password at wp-login.php. The page briefly flashes, and a fraction of a second later you are back at wp-login.php. No "wrong password" message. No visible error. Sometimes the URL shows wp-login.php?redirect_to=%2Fwp-admin%2F in the address bar. Sometimes the browser gives up and shows ERR_TOO_MANY_REDIRECTS. Either way, the credentials worked, the dashboard never loads, and nothing in the form itself tells you why.

This only happens after you submit the form. If the login form rejects you with a visible error, you have a different problem. Start from why you cannot log in to WordPress and follow the account branch.

Common causes, ordered by likelihood

Five root causes cover nearly every real login redirect loop I have seen on WordPress 6.x. They are ordered by how often they turn out to be the actual problem, which is the order you should check them in.

  1. WP_HOME and WP_SITEURL disagree with the URL the browser is on. The site was moved to HTTPS, or a domain was renamed, and the database still holds the old value. The auth cookie is written for one host and the browser sends the next request to a different host. This is the single most common cause, especially right after a migration (see how to migrate WordPress to a new host for the full migration flow).
  2. The site is configured for www.example.com but the user landed on example.com (or vice versa). A variant of the first cause, but worth calling out separately: a host-level redirect is bouncing the browser between the two hostnames, and the auth cookie is dropped during the switch.
  3. FORCE_SSL_ADMIN is true but the server cannot tell it is behind HTTPS. A Cloudflare, nginx, or load balancer front-end terminates TLS and talks plain HTTP to WordPress. WordPress's is_ssl() function checks $_SERVER['HTTPS'] and the server port, not X-Forwarded-Proto, so without extra configuration WordPress thinks the request is HTTP and forces a redirect to HTTPS, which the proxy serves, and the cookie is written for the wrong scheme.
  4. COOKIE_DOMAIN is hard-coded to a domain that does not match the site. A security guide, an old migration, or a copy-paste from another site left a define('COOKIE_DOMAIN', ...) line in wp-config.php that no longer matches reality. The browser silently drops the cookie on the next request.
  5. A plugin is setting WP_HOME at runtime. Some redirect, multilingual, or staging plugins override WP_HOME and WP_SITEURL via a filter like home_url or site_url. The override runs too late to affect cookie writes, so the auth cookie is written for one host and the rest of the page runs as if WordPress were on another.

Before you change anything, rule out the two trivial cases: stale cookies in your browser and a plugin caching layer that is stripping the auth cookie from responses.

Safe pre-flight checks

These are non-destructive. They confirm you are actually in a redirect loop and not in one of the look-alike failures.

Check 1: confirm it is the login loop, not the front-end loop. Open the home page in an incognito window. If the home page itself cycles and shows ERR_TOO_MANY_REDIRECTS, the front end is the problem and the fix lives in Too Many Redirects in WordPress. If the home page loads fine and only wp-login.php bounces you, you are in the right article.

Check 2: rule out stale browser state. Open a fresh incognito window with all extensions disabled. Try logging in there. If it works, the issue was local browser state and you can stop reading. If the loop still happens, the problem is on the server.

Check 3: look at the database value of the site URL. If you can reach phpMyAdmin or a database client, run:

SELECT option_value FROM wp_options WHERE option_name IN ('siteurl', 'home');

Write down both values. They should match exactly, including protocol and the www prefix. If they differ, cause 1 or 2 applies. If they match but the browser is on a different host, cause 2 applies.

Check 4: check whether you are behind a proxy. Open any page of your site in an incognito window and look at the response headers in the browser developer tools. If you see server: cloudflare, an x-amz-cf-id header, or via: entries naming a CDN, your site is behind a proxy that terminates TLS. Cause 3 is in play.

Fix 1: correct WP_HOME and WP_SITEURL after an HTTPS or domain change

This is the fix for the most common cause. If you cannot reach wp-admin, you cannot change the values from the WordPress settings screen, so you override them in wp-config.php which takes priority over the database. Both constants are documented in the wp-config reference.

Open wp-config.php via SFTP or your control panel's file manager. Above the line that says /* That's all, stop editing! Happy publishing. */, add:

// Force the canonical site URL after an HTTPS migration.
// Replace yoursite.nl with the real domain the browser is on.
define('WP_HOME', 'https://yoursite.nl');
define('WP_SITEURL', 'https://yoursite.nl');

Save the file. Clear your browser cookies for the site (this matters: stale cookies from the previous host will block the new ones). Try logging in again.

Verify it worked. You should reach the WordPress dashboard and stay there. Refresh the page once: if you are still logged in after the refresh, the cookie round-trip is healthy. If you are bounced back to wp-login.php on the refresh, the constants are set but something else is still interfering, most likely cause 3 or 4.

Important. Once the loop is fixed, go to Settings -> General inside wp-admin and make sure siteurl and home match what you just set in wp-config.php. The constants are a fix, not a permanent home. If you leave them in wp-config.php forever, any future URL change has to happen in two places instead of one.

Fix 2: resolve a www vs apex URL mismatch

If the database says https://example.com but your browser lands on https://www.example.com (or the opposite), there is a host-level or DNS-level redirect adding or stripping www between login and dashboard. The cookie is written for one host and sent back on a request to the other.

Pick one canonical host. Most modern sites standardise on the apex (example.com without www) because it is shorter and cleaner, but either is fine as long as it is consistent.

Update wp-config.php to match the canonical:

define('WP_HOME', 'https://example.com');
define('WP_SITEURL', 'https://example.com');

Then make sure the server is redirecting the other host to the canonical one, not the other way round. Check any .htaccess redirect rules and any DNS-level or CDN-level forwarding rules. The redirect should be a single hop: visit https://www.example.com, get a 301 to https://example.com, done. No back-and-forth.

Verify it worked. Open an incognito window, visit https://www.example.com/wp-login.php (with www, even though the canonical is apex), and log in. You should be redirected once to https://example.com/wp-admin/ and land inside the dashboard. Refresh the page: you should stay logged in. If the address bar is still switching between www.example.com and example.com after login, the redirect rules still disagree somewhere and the loop will keep happening.

Fix 3: make FORCE_SSL_ADMIN work behind a reverse proxy

If you are behind Cloudflare, a load balancer, or any fronting proxy that terminates TLS, and FORCE_SSL_ADMIN is true, WordPress may not realise the original request is HTTPS. It forces a redirect to the HTTPS version, the proxy hands that request back over plain HTTP, and the scheme detection never recovers. The auth cookie ends up written for the wrong scheme.

The fix has two parts. First, in wp-config.php, trust the X-Forwarded-Proto header that the proxy is sending. Put this above any define that uses site URLs, and above the WordPress bootstrap:

// Tell WordPress the original request was HTTPS when it arrives
// via a reverse proxy that terminated TLS upstream.
if (
    !empty($_SERVER['HTTP_X_FORWARDED_PROTO'])
    && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https'
) {
    $_SERVER['HTTPS'] = 'on';
}

Second, confirm that your proxy is actually sending X-Forwarded-Proto: https. For Cloudflare, this header is present automatically. For nginx in front of Apache, make sure your upstream configuration includes proxy_set_header X-Forwarded-Proto $scheme;. For a load balancer, check the listener configuration.

Verify it worked. Open an incognito window, log in, and land inside the dashboard. Then refresh. You should stay logged in. If you still bounce back to wp-login.php on refresh, the proxy is not sending X-Forwarded-Proto, or the snippet is placed below code that already read $_SERVER['HTTPS'].

Do not disable FORCE_SSL_ADMIN as your fix. It is tempting to set define('FORCE_SSL_ADMIN', false); and call it done. That stops the loop but leaves your admin login unencrypted at the application level on the inside of the proxy, which defeats the point of having it. Fix the scheme detection properly.

Fix 4: remove or correct a hard-coded COOKIE_DOMAIN

Open wp-config.php in your hosting panel's file manager or via SFTP and search for COOKIE_DOMAIN (use Ctrl+F or Cmd+F in the editor).

If you have SSH access:

grep -n COOKIE_DOMAIN /path/to/wordpress/wp-config.php

If you see a line like define('COOKIE_DOMAIN', '.example.com'); and the current site is on a different domain, that is your loop. In a single-site WordPress, you almost never need COOKIE_DOMAIN at all. Delete the line entirely and let WordPress default to an empty domain attribute, which means "whatever host the browser is talking to". That is the correct behaviour for 99% of installs.

If you need COOKIE_DOMAIN set (for example, for a multisite install with a specific subdomain strategy), make sure the value matches exactly. .example.com with a leading dot is valid and covers subdomains. example.com without a dot covers only the exact host.

Verify it worked. Save wp-config.php, clear browser cookies for the site, try to log in. You should stay logged in after the dashboard loads and after a refresh. If the loop is still happening, the problem is not COOKIE_DOMAIN and you should move on to cause 5.

Fix 5: stop a plugin from setting WP_HOME at runtime

This one is rarer but painful when it hits, because every other fix looks correct. A plugin (often a redirect manager, a multilingual plugin with domain-per-language, or a staging workflow plugin) hooks into home_url or site_url and rewrites the return value. The auth cookies have already been written by the time that filter fires, so the cookie is for one host and the rest of the page runs as if it were on another.

To test this, disable all plugins by renaming the plugins directory. Open your hosting panel's file manager or an SFTP client, navigate to wp-content, and rename the plugins folder to plugins_off.

If you have SSH access:

mv wp-content/plugins wp-content/plugins_off

Try logging in. If the loop is gone, a plugin is the cause. Rename the directory back to plugins (via the file manager or SFTP, or mv wp-content/plugins_off wp-content/plugins over SSH).

Then, inside wp-content/plugins, rename each subdirectory one at a time with a suffix like _off, try logging in after each, and the one whose rename fixes the loop is the culprit. Pay special attention to WPML, Polylang, Redirection, and any staging or domain-mapping plugin.

Verify it worked. With the culprit plugin deactivated, log in, refresh, and navigate around wp-admin. If everything holds, the plugin is confirmed. Your next step is either to reconfigure the plugin properly (most of them have a setting for "site URL" that needs to match WP_HOME exactly) or to replace it with something that does not override core URL functions.

Baseline fallback: cookies, incognito, plugin deactivation

If none of the five specific causes match, go back to basics in this order. Each step is a one-minute check and collectively they catch the long-tail cases I did not list above.

  • Clear cookies for your site in the browser. Not the whole browser history, just the cookies for the specific domain. Reload wp-login.php and try again. This fixes the case where a dead cookie from yesterday's broken state is still blocking the new one. If you get a "Cookies are blocked" message on the login page instead of a silent loop, you are looking at a different symptom: read cookies are blocked or not supported in WordPress instead.
  • Test in a different browser. If Chrome is stuck in the loop but Firefox works, the issue is browser-local (an extension, a cached redirect, or a strict privacy profile) and not on the server.
  • Test in incognito with all extensions disabled. Same idea, but it rules out extensions specifically.
  • Check for a page cache that is stripping auth cookies. Some caching plugins and most CDN page caches have a rule that ignores or strips cookies on cached responses. If wp-admin itself is being served from cache, the auth cookie never makes it back. The fix is to add wp-admin and wp-login.php to the cache bypass rules in the plugin or CDN.

If none of this helps, the problem is specific enough that remote diagnosis becomes unreliable. Move to the escalation section.

When to escalate

If you have worked through every cause and the loop is still happening, ask for help with the following information collected. A host or WordPress specialist cannot do much without it, and gathering it first saves at least one round of back-and-forth.

  • The exact URL you land on after login (copy the full URL from the address bar when you are bounced back)
  • The values of siteurl and home in wp_options (from the SQL in Check 3)
  • The contents of wp-config.php, with any database credentials redacted. Specifically: any define that mentions WP_HOME, WP_SITEURL, COOKIE_DOMAIN, FORCE_SSL_ADMIN, or $_SERVER['HTTPS']
  • Whether the site is behind Cloudflare, a load balancer, or another proxy
  • The full plugin list (a screenshot of Plugins -> Installed Plugins or the output of wp plugin list if you have WP-CLI)
  • The WordPress version, PHP version, and host name
  • The browser name and version you are testing with, and whether the loop also happens in a second browser
  • A note of which of the five fixes on this page you have already tried and the result of each

If you want WordPress to log what is happening, enable debug logging via wp-config.php (WP_DEBUG documentation):

define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);

The log lands at wp-content/debug.log. Reproduce the loop once, then include the tail of that file in your escalation.

Preventing the loop from coming back

A few habits avoid almost every future occurrence of this loop.

  • Standardise on one canonical host and enforce it at the web server, not inside WordPress. Pick apex or www, pick https, and use a single web server redirect to send everything else there.
  • Never hard-code COOKIE_DOMAIN in a single-site install. The default (empty) value is the correct value for almost everyone, and hard-coding it is how most post-migration loops start. For the upstream HTTPS setup, see how to force WordPress to HTTPS correctly.
  • When you do an HTTPS migration or a domain change, update both wp-config.php and the wp_options values in the same change. Leaving the database with an old value is what causes the mismatch.
  • If your site is behind a proxy, set the X-Forwarded-Proto bridge once and forget about it. Put the snippet from Fix 3 in wp-config.php from day one and you will never hit cause 3.
  • Test login after every migration, TLS certificate change, or plugin update that touches redirects. It takes ten seconds and it is the cheapest way to catch this symptom before a real user does.

Locked out of wp-admin too often?

Login and access issues usually come down to changes, conflicts or security rules. WordPress maintenance reduces surprises with controlled updates and checks.

See WordPress maintenance

Search this site

Start typing to search, or browse the knowledge base and blog.