You type the correct password. WordPress smiles politely… and punts you right back to the login screen. No error. No explanation. Just an endless loop between wp-login.php and wp-admin/, like your site is gaslighting you.
This is usually not “a WordPress bug.” It’s WordPress doing exactly what it should: refusing to consider you authenticated because cookies, redirects, HTTPS, caching, or session-handling are broken somewhere in the chain. The trick is to stop guessing and follow the evidence.
Fast diagnosis playbook (check these first)
If you only have five minutes before someone important asks why they can’t publish the CEO’s blog post, do this in order. This sequence finds the bottleneck quickly because it follows the authentication path: browser → edge cache → reverse proxy → PHP → database.
1) Confirm whether cookies are being set and returned
- Check: Does the browser receive
Set-Cookieafter POSTing credentials? - Then: Does the next request to
/wp-admin/include that cookie? - Why: A login “loop” is often WordPress saying “I didn’t get a valid auth cookie,” so it sends you back.
2) Confirm your canonical URL and scheme are consistent
- Check: Are you bouncing between
httpandhttpsor betweenwwwand apex? - Why: Cookies are scoped to domain + scheme rules. If your login POST happens on one host/scheme and admin loads on another, your cookie may not apply.
3) Bypass caches and security layers
- Check: Is an edge cache, WAF, “performance” plugin, or reverse proxy caching
wp-login.phpor mangling headers? - Why: Auth endpoints are dynamic. Caching them is like labeling your front door “sometimes open.”
4) Disable plugins safely, then themes
- Check: Does the problem disappear with plugins disabled?
- Why: One “security” or “cookie consent” plugin can break auth in creative ways.
5) Validate server-side sessions, PHP, and DB writes
- Check: Is PHP writing sessions? Is the DB writable? Any fatal errors?
- Why: If WordPress can’t set auth-related state (or you have object cache weirdness), it can’t keep you logged in.
How the WordPress login flow actually works (so you stop fighting ghosts)
WordPress login is cookie-based. When you submit credentials to wp-login.php, WordPress:
- Validates username/password (or SSO) and checks user status/capabilities.
- Issues authentication cookies: typically
wordpress_logged_in_*andwordpress_sec_*(names vary with hash/salt and settings). - Redirects you (302) to
/wp-admin/or a target path. - On the next request, WordPress reads cookies, validates them against salts and the user record, and either allows access or redirects back to login.
A “login loop” means one of three things:
- The cookie never got set (blocked, stripped, cached response, wrong headers).
- The cookie was set but never sent back (domain mismatch, secure flag mismatch, path mismatch, SameSite issues in certain flows).
- The cookie was sent but rejected (bad salts after migration, DB/object cache inconsistency, time skew, user meta weirdness, custom auth plugin).
One practical mantra: treat this like distributed systems debugging. There are multiple layers, and any one layer can “helpfully” rewrite your request into failure.
Quote, as a paraphrased idea from a reliability heavyweight: paraphrased idea — “Hope is not a strategy.”
— attributed to Gene Kranz (mission operations mindset).
Joke #1: A WordPress login loop is the only cardio some of us get in a workday. It’s not a good wellness program.
Interesting facts and historical context (short, useful)
- Fact 1: WordPress has used cookie-based auth since early releases; the cookie names include hashes derived from site settings and security salts, which is why migrations can “randomly” break logins.
- Fact 2: The
wp-login.phpendpoint is one of the most targeted public URLs on the internet; many hosting stacks add WAF rules or rate limiting that can subtly interfere with legitimate logins. - Fact 3: The admin area relies on redirects heavily (canonical host, SSL enforcement, admin location). Redirect misconfiguration produces loops faster than almost any other site bug.
- Fact 4: Browsers have tightened cookie handling over time (notably around SameSite defaults), which can break login flows involving cross-site POSTs or external IdP callbacks if you don’t set cookies correctly.
- Fact 5: Many “cache everything” CDNs originally shipped with naive defaults; modern setups usually exclude
wp-adminandwp-login.php, but it still gets misconfigured constantly. - Fact 6: WordPress stores the canonical URLs (
homeandsiteurl) in the database, but allows overrides viawp-config.php. Conflicts between the two are a classic loop generator. - Fact 7: A reverse proxy (load balancer, CDN, ingress) changes the meaning of “is this HTTPS?” unless forwarded headers are correct; WordPress uses that to decide cookie security flags and redirect targets.
- Fact 8: Object caching (Redis/Memcached) can make authentication feel “haunted” when stale values persist across deploys or when multiple app servers disagree on salts/config.
The real causes of the login loop (ranked by how often they hurt)
1) URL, host, or HTTPS mismatch (the canonical redirect treadmill)
WordPress wants one true URL for the site. If your stack serves multiple variants—http, https, with/without www, maybe an alternate domain—the login POST might happen on one variant, but the redirect to /wp-admin/ lands on another. Cookies don’t travel the way you wish they would.
Common triggers:
homeandsiteurlset differently (one http, one https).- Forced HTTPS at the load balancer, but WordPress thinks it’s plain HTTP.
- Redirect rules in Nginx/Apache fighting with WordPress’s own canonical redirects.
2) Cookies blocked, stripped, or scoped wrong
If cookies aren’t set or returned, WordPress can’t keep you logged in. Causes include:
- Proxy/CDN stripping
Set-Cookieheaders for “cacheability.” - Cookie domain/path mismatch after a domain change.
- Secure cookies over HTTPS not working because WordPress doesn’t detect HTTPS (so it sets non-secure cookies, then you get redirected to HTTPS and they aren’t accepted as expected).
- Misbehaving cookie consent or security plugins rewriting headers.
3) Cache (edge, plugin, server) caching the wrong thing
It’s impressive how many “performance” configurations try to cache login pages. If the login response or redirect is cached, different users start sharing the same broken state. Also, if a cache removes cookies, auth breaks invisibly.
4) Plugin/theme conflicts, especially security and SSO
Security plugins, SSO bridges, 2FA plugins, and “disable XML-RPC” style bundles often hook into authentication filters. One bad update can introduce a redirect rule that never completes.
5) Broken salts/keys after migration or config drift across servers
WordPress signs auth cookies with salts and keys in wp-config.php. If you change them, existing cookies become invalid (which is fine), but if you have multiple app servers with different salts, users get logged out or loop depending on which backend they hit.
6) Time skew or TLS termination weirdness
Auth cookies contain expiration. If system time is wrong (VM drift, container clock issues, NTP broken), cookies can appear expired immediately. Less common, but spectacular when it happens.
7) Database or filesystem write failures and subtle fatals
WordPress auth relies on DB reads/writes and PHP being able to complete requests. If PHP is fataling after setting a redirect, or the DB is read-only, you can end up in a loop with little user-facing error. Check logs like you mean it.
Hands-on tasks: commands, outputs, and decisions (12+)
These are practical tasks you can run on a typical Linux host. Adjust paths if your distro or layout differs. Each task includes: command, what output means, and the decision you make next.
Task 1: Reproduce the redirect chain from the server side
cr0x@server:~$ curl -I -L https://example.com/wp-admin/ | sed -n '1,40p'
HTTP/2 302
location: https://example.com/wp-login.php?redirect_to=https%3A%2F%2Fexample.com%2Fwp-admin%2F&reauth=1
set-cookie: wp-wpml_current_language=en; path=/
server: nginx
HTTP/2 200
content-type: text/html; charset=UTF-8
cache-control: no-store, no-cache, must-revalidate, max-age=0
What it means: A single 302 to login is normal if you aren’t authenticated. If you see repeated 302s bouncing between wp-login.php and wp-admin, you have a loop.
Decision: If loop appears here without a browser, you’re dealing with server-side redirect logic or canonical URL issues—not “my browser is weird.”
Task 2: Check if login page responses are being cached by a proxy/CDN
cr0x@server:~$ curl -I https://example.com/wp-login.php | egrep -i 'cache|age|cf-cache-status|x-cache|via|set-cookie'
cache-control: no-store, no-cache, must-revalidate, max-age=0
set-cookie: wordpress_test_cookie=WP%20Cookie%20check; path=/; secure; HttpOnly
What it means: You want no-store or similarly restrictive caching. If you see headers like x-cache: HIT or a CDN “cache status” showing a cache hit, that’s suspicious.
Decision: If cached, configure the CDN/reverse proxy to bypass cache for /wp-login.php and /wp-admin/*, and to never strip Set-Cookie.
Task 3: Confirm WordPress canonical URLs (WP-CLI)
cr0x@server:~$ cd /var/www/html
cr0x@server:/var/www/html$ wp option get home
https://example.com
cr0x@server:/var/www/html$ wp option get siteurl
http://example.com
What it means: That mismatch (https vs http) is a classic loop trigger.
Decision: Set them to the same scheme and host. Pick one canonical URL and stick to it.
Task 4: Fix home and siteurl safely
cr0x@server:/var/www/html$ wp option update home 'https://example.com'
Success: Updated 'home' option.
cr0x@server:/var/www/html$ wp option update siteurl 'https://example.com'
Success: Updated 'siteurl' option.
What it means: WordPress will generate cookies/redirects based on these values.
Decision: Retest login. If still looping, move to HTTPS detection and proxy headers.
Task 5: Check whether WordPress thinks the request is HTTPS (behind a proxy)
cr0x@server:~$ grep -R "HTTPS" -n /var/www/html/wp-config.php | head
# (no output)
What it means: No explicit forcing of HTTPS at the app level. That’s fine if your proxy headers are correct, but risky when they aren’t.
Decision: If you terminate TLS at a load balancer and forward to PHP over HTTP, ensure X-Forwarded-Proto is set and honored, or set $_SERVER['HTTPS']='on' conditionally in wp-config.php.
Task 6: Verify forwarded headers at Nginx (common culprit)
cr0x@server:~$ sudo nginx -T 2>/dev/null | egrep -n "X-Forwarded-Proto|X-Forwarded-For|fastcgi_param"
112: proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
113: proxy_set_header X-Forwarded-Proto $scheme;
210: fastcgi_param HTTPS $https if_not_empty;
What it means: If you’re behind a proxy, $scheme might be http between proxy and origin even when the client used HTTPS. That makes WordPress believe it’s on HTTP.
Decision: Set forwarded proto correctly from the edge (LB → origin). Often you want Nginx to trust X-Forwarded-Proto from your LB and pass it to PHP.
Task 7: Inspect response headers for missing/rewritten cookies
cr0x@server:~$ curl -s -D - https://example.com/wp-login.php -o /dev/null | sed -n '1,40p'
HTTP/2 200
date: Fri, 27 Dec 2025 11:20:00 GMT
content-type: text/html; charset=UTF-8
set-cookie: wordpress_test_cookie=WP%20Cookie%20check; path=/; secure; HttpOnly
What it means: You’re getting Set-Cookie at least for the test cookie. After posting credentials, you should see auth cookies too.
Decision: If Set-Cookie disappears only on POST, suspect WAF rules, caching, or a plugin that dies mid-response.
Task 8: Post to wp-login.php and check for auth cookies (server-side simulation)
cr0x@server:~$ curl -s -D - -o /dev/null -X POST https://example.com/wp-login.php \
-d "log=admin&pwd=wrongpassword&wp-submit=Log+In&redirect_to=https%3A%2F%2Fexample.com%2Fwp-admin%2F&testcookie=1" | egrep -i 'HTTP/|set-cookie:|location:'
HTTP/2 200
set-cookie: wordpress_test_cookie=WP%20Cookie%20check; path=/; secure; HttpOnly
What it means: With wrong credentials you won’t get auth cookies; you should get a 200 with the error page.
Decision: If even correct creds don’t produce auth cookies (you’d see additional set-cookie lines), move to PHP logs and plugin isolation.
Task 9: Check PHP-FPM and web logs for auth-related fatals
cr0x@server:~$ sudo tail -n 80 /var/log/php8.2-fpm.log
[27-Dec-2025 11:18:32] WARNING: [pool www] child 2147 said into stderr: "PHP Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/wp-content/plugins/foo/foo.php:12) in /var/www/html/wp-includes/pluggable.php on line 1428"
What it means: “Headers already sent” can prevent cookies from being set. No cookies, no login. That plugin file output something (even whitespace) before WordPress could set headers.
Decision: Disable the offending plugin. Then fix it properly (or replace it) because this will keep coming back.
Task 10: Disable plugins without needing wp-admin
cr0x@server:~$ cd /var/www/html
cr0x@server:/var/www/html$ wp plugin deactivate --all
Success: Deactivated 14 of 14 plugins.
What it means: You’ve removed plugin interference from the equation.
Decision: Retest login. If fixed, re-enable plugins one at a time to find the offender (yes, it’s tedious; yes, it’s faster than guessing).
Task 11: Switch to a default theme to eliminate theme-level auth hacks
cr0x@server:/var/www/html$ wp theme list
+----------------+----------+--------+---------+
| name | status | update | version |
+----------------+----------+--------+---------+
| twentytwentyfour | inactive | none | 1.2 |
| corp-theme | active | none | 4.8.1 |
+----------------+----------+--------+---------+
cr0x@server:/var/www/html$ wp theme activate twentytwentyfour
Success: Switched to 'Twenty Twenty-Four' theme.
What it means: If your theme has custom login redirects, SSO hooks, or broken output buffering, this isolates it.
Decision: If this fixes the loop, your “beautiful corporate theme” is now a production incident. Treat it accordingly.
Task 12: Check config drift of salts/keys across servers (quick diff)
cr0x@server:~$ sudo egrep "AUTH_KEY|SECURE_AUTH_KEY|LOGGED_IN_KEY|NONCE_KEY" -n /var/www/html/wp-config.php
54:define('AUTH_KEY', '...a...');
55:define('SECURE_AUTH_KEY', '...b...');
56:define('LOGGED_IN_KEY', '...c...');
57:define('NONCE_KEY', '...d...');
What it means: These values must be identical on all app servers behind a load balancer.
Decision: If you have multiple origins, verify they match everywhere. If they don’t, fix deployment so configuration is consistent.
Task 13: Check system time and NTP sync (cookie expiry sanity)
cr0x@server:~$ timedatectl
Local time: Fri 2025-12-27 11:20:44 UTC
Universal time: Fri 2025-12-27 11:20:44 UTC
RTC time: Fri 2025-12-27 11:20:44
Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
What it means: If clocks are off or NTP is inactive, cookies can appear instantly expired.
Decision: If unsynchronized, fix time first. Don’t debug authentication on a server that can’t agree on “now.”
Task 14: Check Redis object cache health (if used)
cr0x@server:~$ redis-cli ping
PONG
cr0x@server:~$ redis-cli info | egrep "used_memory_human|maxmemory_human|evicted_keys"
used_memory_human:312.45M
maxmemory_human:512.00M
evicted_keys:18422
What it means: Lots of evictions can cause weird behavior. Not always login loops, but it can destabilize auth-related cached values in some setups.
Decision: If eviction is high, increase cache memory or reduce cache usage. Also confirm your object cache plugin is appropriate and configured.
Task 15: Confirm DB is writable and not returning errors
cr0x@server:~$ mysql -N -e "SHOW GLOBAL VARIABLES LIKE 'read_only';"
read_only OFF
What it means: If DB is read-only (or failing), WordPress can behave unpredictably, especially with sessions/plugins writing user meta.
Decision: If read-only is ON unexpectedly, fix replication/failover state or point WordPress to the correct primary.
Task 16: Validate that wp-content is not read-only (updates and some auth flows)
cr0x@server:~$ sudo -u www-data test -w /var/www/html/wp-content && echo "wp-content writable" || echo "wp-content NOT writable"
wp-content writable
What it means: Not every login loop is about file writes, but permission issues often accompany broken deployments and “headers already sent” problems.
Decision: If not writable and your stack expects it, fix ownership/permissions; if your stack forbids writes, ensure plugins/themes don’t attempt runtime writes in ways that break responses.
Common mistakes: symptom → root cause → fix
Symptom: Correct password, instant redirect back to wp-login.php, no error
Root cause: Cookies not being stored or returned (domain mismatch, secure flag mismatch, headers already sent, proxy stripping Set-Cookie).
Fix: Verify home/siteurl consistency, check response headers for Set-Cookie, eliminate “headers already sent” PHP warnings, and disable caches on login/admin.
Symptom: Works on one browser/device, fails on another
Root cause: Cookie policy differences (SameSite behavior, third-party cookie blocking), stale cookies, or a browser extension modifying requests.
Fix: Test in a clean profile/incognito, clear site cookies, ensure your login flow is first-party (no cross-site POST surprises), and confirm HTTPS and canonical host.
Symptom: Works on origin directly, fails through CDN/WAF
Root cause: Edge caching of login/admin, WAF challenge pages, header stripping, or bot protection treating humans like bots.
Fix: Bypass cache for auth endpoints, allowlist admin IP ranges if appropriate, and ensure challenge pages don’t apply to wp-login.php POSTs.
Symptom: Only fails when “Force HTTPS” or HSTS is enabled
Root cause: WordPress doesn’t detect HTTPS behind a proxy; it sets cookies or redirects inconsistently.
Fix: Correct forwarded headers and/or set HTTPS detection in wp-config.php. Ensure only one layer performs the canonical redirect.
Symptom: Random logouts / loops in a load-balanced setup
Root cause: Different salts/keys across app servers, inconsistent wp-config.php, or sticky sessions missing when required by a plugin.
Fix: Make configuration immutable and identical across nodes. Avoid reliance on sticky sessions; if unavoidable, configure them explicitly and document why.
Symptom: Login works, but wp-admin immediately logs out after a few clicks
Root cause: Cache plugin caching admin-ajax responses, aggressive security plugin invalidating sessions, or clock skew.
Fix: Exclude admin paths from cache, tune security rules, and verify time sync.
Symptom: Only admins affected; editors can log in
Root cause: Admin-specific redirect policies, 2FA enforcement misconfiguration, capability checks, or custom mu-plugin.
Fix: Inspect must-use plugins and security settings; test with all plugins disabled; review server logs for role-specific redirects.
Checklists / step-by-step plan
Checklist A: One-pass “get me back into wp-admin” recovery
- Clear browser cookies for the site (or use a private window). If you can’t log in there either, it’s not “stale cookies.”
- Confirm canonical URL:
- Make
homeandsiteurlidentical (scheme + host). - Pick either
wwwor apex and stick to it.
- Make
- Bypass the CDN/WAF temporarily (host file / direct origin) to see if the edge is the problem.
- Disable all plugins via WP-CLI or by renaming
wp-content/plugins. - Switch to a default theme to rule out theme auth code.
- Check logs for “headers already sent” and fatal errors.
- Fix HTTPS detection behind proxies (forwarded headers or conditional HTTPS forcing in
wp-config.php). - Re-enable plugins one at a time. Stop when the loop returns. That plugin is your culprit, not your victim.
Checklist B: Hardening so this doesn’t come back next Tuesday
- Exclude auth endpoints from caching:
/wp-login.php,/wp-admin/*, and typically/wp-json/as needed for your admin flows. - Standardize config deployment: one source of truth for
wp-config.phpand salts, delivered identically to all nodes. - Monitor redirects: track 302 rates for
wp-login.phpandwp-admin. A spike is often an early warning. - Log at the edge and origin: include request IDs so you can trace a single login attempt through the stack.
- Document your canonical URL policy (host, scheme, HSTS). Unwritten policy becomes folklore; folklore becomes incidents.
- Test after changes: whenever you touch CDN rules, HTTPS termination, or caching plugins, test login flow explicitly.
Joke #2: The fastest way to create a WordPress login loop is to say, “It’s just a small redirect change.” The loop hears you.
Three corporate mini-stories from the trenches
Incident #1: The wrong assumption (HTTPS is HTTPS, right?)
A mid-sized company ran WordPress behind a load balancer that terminated TLS. The origin servers spoke plain HTTP internally. The team assumed that because the browser showed a lock icon, the application “knew” it was HTTPS.
One afternoon, editors reported the login loop. It wasn’t everyone—just enough people to trigger a panic and a Slack storm. The load balancer had been replaced as part of a network refresh, and the default header behavior changed.
On the origin, WordPress started seeing requests as HTTP. It responded with redirects to HTTPS (because home was https), but it also set cookies in a way that didn’t align with the browser’s expectations. The auth cookie story became inconsistent across requests. Users logged in, got redirected, then got treated like strangers and sent back.
The fix was boring: ensure X-Forwarded-Proto: https was set correctly at the edge, and ensure the origin trusted it consistently. Once WordPress had a stable view of scheme, the loop disappeared.
The lesson: in a proxied world, “HTTPS” is not a fact—it’s a claim conveyed by headers. If you don’t explicitly manage that claim, your application will make up its own reality.
Incident #2: The optimization that backfired (cache all the things)
A different org had a performance initiative. Someone enabled an aggressive CDN rule to cache more HTML, including “low-risk pages.” wp-login.php looked like “just another page” in a ruleset. That was the first mistake.
Within hours, login success rates dropped. Not to zero—just enough to be confusing. The CDN served cached login pages that contained stale nonces and inconsistent redirect targets. Even worse, some cached responses didn’t include Set-Cookie properly, depending on how the edge treated “uncacheable” headers.
The incident got political because the change was framed as “performance work,” and performance work is supposed to be heroic. Instead, it turned authentication into probabilistic theater.
The fix was to create explicit bypass rules for all auth-related endpoints and anything that sets sensitive cookies. Then they added a synthetic monitor that performed a login flow and alerted on unexpected redirect chains.
The lesson: caching is not a blanket. It’s a scalpel. If you swing it like a hammer, you will eventually hit your own login system.
Incident #3: The boring but correct practice that saved the day (config immutability)
A company ran WordPress on multiple application servers. They had a strict practice: configuration, including salts and keys, was managed centrally and deployed identically with every release. No hand-edits. No “quick fixes” on individual nodes.
They still had an incident—an engineer added a new node under pressure. The node came from an older image and initially had a mismatched wp-config.php. In many environments, that would create random login loops depending on which backend a user hit.
Here’s what saved them: their deployment pipeline detected drift. The new node failed a config checksum check and never entered the load balancer pool. The login loop never reached customers; it stayed a staging problem where it belonged.
They fixed the image, redeployed, and moved on. No late-night “why does it only happen to some users” detective work.
The lesson: the most reliable auth fix is preventing inconsistency. The second-most reliable fix is not letting inconsistent nodes serve traffic.
FAQ
Why does WordPress keep redirecting me to the login page after I log in?
Because WordPress isn’t receiving or accepting a valid auth cookie on the subsequent request. That’s usually caused by URL/scheme mismatch, cookie scoping issues, caching, proxy headers, or a plugin interfering with headers.
Is clearing cookies the real fix?
Clearing cookies is a diagnostic step. If it fixes the issue once, you likely changed salts/keys recently or had a transient cookie mismatch. If it never fixes it, the problem is in the stack, not the browser.
Can a CDN or WAF cause a login loop?
Absolutely. If it caches wp-login.php, strips Set-Cookie, or challenges POST requests, you can get stuck in a loop. Bypass the edge to confirm, then add explicit bypass rules.
What’s the difference between home and siteurl, and why does it matter?
siteurl is where WordPress core files live; home is what the site considers its public URL. If these disagree (especially scheme/host), redirects and cookie scope can break authentication.
I’m behind a load balancer. What header matters most?
X-Forwarded-Proto. If it’s wrong or not trusted, WordPress may believe it’s on HTTP even when the client is on HTTPS, leading to broken redirects and cookie flags.
Could this be a plugin even if the site works fine for visitors?
Yes. Public pages can work while admin/auth endpoints break because plugins hook into login, redirect, security checks, and header handling. Disable plugins to prove it.
Why does it only happen to some users in a load-balanced setup?
Usually config drift (different salts/keys) or statefulness assumptions. If one backend rejects cookies created by another backend, you get “works sometimes” behavior. Make config identical and avoid stateful hacks.
Will resetting WordPress salts fix the login loop?
Resetting salts invalidates all sessions, which can “fix” loops caused by inconsistent or compromised cookies. But if the root cause is proxy headers, caching, or URL mismatch, it won’t help—your users will just be logged out and still stuck.
What if I can’t access wp-admin or WP-CLI at all?
Rename the plugins directory via SSH to disable all plugins: wp-content/plugins → plugins.disabled. If that fixes login, reintroduce plugins carefully. If not, focus on home/siteurl and proxy/HTTPS detection.
Conclusion: next steps that prevent reoccurrence
Fixing a WordPress login loop is less about heroics and more about refusing to be lied to by your own stack. Follow the cookies. Follow the redirects. Confirm what WordPress thinks the canonical URL is, and confirm what the browser is actually doing.
Practical next steps:
- Make
homeandsiteurlmatch exactly (scheme + host). - Ensure your proxy/CDN does not cache or modify
wp-login.phpand/wp-admin/, and never stripsSet-Cookie. - Verify HTTPS detection behind proxies via forwarded headers.
- Disable plugins/themes to isolate header output and auth hooks; re-enable one by one.
- Standardize
wp-config.php(especially salts/keys) across all nodes and keep time synchronized.
If you do those five things, the login loop goes back to what it should be: a story you tell other engineers, not a place you live.