WordPress 'Your Session Has Expired' Keeps Logging You Out? Here's the Real Fix
You are in the middle of editing a post and WordPress throws a 'Your session has expired. Please log in again to continue' banner across the editor. Log back in, and it happens again 15 minutes later. This guide walks through why the session dies so fast, the cookie and cache misconfigurations that trigger it, and the fixes that actually keep you logged in.

What's Happening
You are three paragraphs into a post inside the block editor and a modal appears in the middle of the screen: 'Your session has expired. Please log in again to continue.' You click the log-in link, sign back in, come back to the editor, and either the draft is saved (great) or half the paragraph you were writing is gone (not great). Twenty minutes later it happens again. The session should last at least two days on a normal WordPress install, so if it is dying every few minutes something in the cookie, cache, or security layer is killing it early.
The 'Your session has expired' banner is one of those WordPress errors that never shows up in a debug log because, from WordPress's point of view, nothing is broken. Core issued you a cookie at login, the next request came in without a valid cookie, and core did exactly what it was designed to do: assume the session ended and ask you to sign in again. The problem is upstream of WordPress: the cookie is being stripped, rejected, or invalidated by something between the browser and PHP.
In 12 years of fixing WordPress sites I have seen this error trace back to a handful of specific causes over and over: a cache plugin serving admin pages from cache, a Cloudflare rule caching /wp-admin/, an https/http URL mismatch that made the cookie invalid, a security plugin binding sessions to a single IP, and a browser extension blocking cookies it thinks are trackers. Each cause has a clean fix. The trick is figuring out which one you are hitting before you start changing settings.
This guide walks through the diagnosis in the order I actually run it on a paid recovery job, so you spend 10 minutes finding the cause instead of an hour trying every fix you can find on Google.
The five real causes, in the order I check them
Every session expired case I have troubleshot in the last few years has been one of these. Rule them out top to bottom and you will find it.
- A caching layer (plugin, hosting cache, or Cloudflare) is serving cached responses to logged-in requests
- The site URL and WordPress Address in Settings > General do not match the URL the browser is actually loading (www vs non-www, http vs https, trailing slash)
- A security plugin is binding sessions to IP address and your IP changed
- The browser or an extension is blocking or stripping the WordPress cookies
- The SECURE_AUTH_KEY constants in wp-config.php were regenerated (accidentally or during a migration) and every existing cookie is now invalid
Step 1: Check for URL mismatches
Open Settings > General and look at the WordPress Address (URL) and Site Address (URL) fields. Both should match, and both should match the exact URL you use in the browser. If your address bar shows https://www.example.com and Settings shows https://example.com, cookies set on www.example.com will not be sent back on example.com and every admin request will fail the cookie check.
The fix is to pick one canonical form (I recommend https://www.yourdomain.com), set both fields to it, save, and add a 301 redirect at the server level so any request to the other form is redirected before it reaches WordPress. On Apache that goes in .htaccess, on Nginx it goes in the server block.
# Force https + www at the .htaccess level, before WordPress loads
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>Step 2: Kill every cache in the stack
Do this in order and test the login after each layer. Browser cache first (Ctrl+Shift+Delete, last hour, cookies and cached files). Then WordPress cache plugin (WP Rocket has a Clear Cache button in the top bar, LiteSpeed has one under LiteSpeed Cache > Toolbox > Purge, W3TC under Performance > Dashboard > empty all caches). Then hosting cache (SiteGround Optimizer, Kinsta cache, WP Engine cache, Cloudways Varnish). Then Cloudflare (Dashboard > Caching > Purge Everything).
After each purge, open a fresh incognito window and try to log in and edit a post for a few minutes. If the banner comes back within one purge cycle, that layer is not the cause. If the banner stops after purging one specific cache but returns as soon as content is re-cached, that layer is misconfigured and needs an exclusion rule for admin URLs.
Step 3: Exclude admin URLs from every cache
Every real cache plugin can be configured to skip caching for logged-in users and to never cache admin URLs. Those settings default to on when you install the plugin, but they get switched off surprisingly often. In WP Rocket it is Cache > Never Cache (URLs) with entries for /wp-admin/, /wp-login.php, /wp-json/. In LiteSpeed Cache it is Cache > Excludes with the same entries plus 'Do Not Cache Logged-in Users' set to ON.
For Cloudflare, create a Cache Rule (Caching > Cache Rules > Create rule) with a hostname match on your domain and a path match on /wp-admin/*, /wp-login.php, or /wp-json/*, then set the action to 'Bypass cache'. Do the same for any URL containing the string 'preview=true' if you use the block editor's preview feature. This one rule alone fixes about a third of the session expired cases I see on Cloudflare-fronted sites.
Cloudflare > Caching > Cache Rules > Create rule
Name: Bypass cache for WordPress admin
When incoming requests match:
(http.request.uri.path contains "/wp-admin/") or
(http.request.uri.path contains "/wp-login.php") or
(http.request.uri.path contains "/wp-json/")
Then:
Cache eligibility: Bypass cacheStep 4: Rule out a security plugin binding sessions to IP
Wordfence, Solid Security (formerly iThemes), All in One WP Security, and Sucuri all ship with optional settings that tie a session to the IP address it was created on. The setting is well intentioned, it makes stolen cookies harder to reuse, but on any network where your IP changes mid-session (a laptop moving between Wi-Fi and cellular, a home ISP with dynamic IP, a VPN that rotates exit nodes) it looks exactly like session expired.
In Wordfence: All Options > Firewall Options > Advanced Firewall Options > 'Lock out invalid users when they trigger a rule' and 'Immediately block IPs that access these URLs'. In Solid Security: Advanced > Local Brute Force Protection and Session Hijacking. Turn off IP binding, or add every network you use to the allow list, then log out and back in to issue a fresh cookie that is not bound to the old IP.
Step 5: Test in a clean browser profile
This step catches the browser-side causes that no server-side troubleshooting will find. Open Chrome, Firefox, or Edge in a fresh profile (File > New Profile) or use an incognito window with all extensions disabled. Sign in to your WordPress admin and try to reproduce the session expired banner.
If the banner does not appear in the clean profile, the cause is a browser extension or a privacy setting in your normal profile. Common offenders in 2026: uBlock Origin with an over-aggressive cookie filter, Privacy Badger, Ghostery, Brave's Shields on Aggressive, and Safari's Intelligent Tracking Prevention when your admin URL is on a different subdomain from the front end. Add your admin URL to the allowlist of each and the banner disappears.
Step 6: Check the wp-config.php auth keys
Open wp-config.php and find the block of eight define lines starting with AUTH_KEY and ending with NONCE_SALT. Those secrets sign every auth cookie the site issues. If they changed for any reason (someone regenerated them, a migration tool wrote new ones, a security plugin rotated them on a schedule) every cookie issued before the change is now invalid, and users get logged out immediately.
You can regenerate them intentionally to force everyone out and reset the login state, but do not regenerate them casually. Every user needs to log in again after the change. Grab a fresh set from api.wordpress.org/secret-key/1.1/salt/ and paste them over the existing block. Save, and log in fresh.
// wp-config.php: the eight secret keys that sign auth cookies
// Get a new set at: https://api.wordpress.org/secret-key/1.1/salt/
define('AUTH_KEY', 'put a long random string here');
define('SECURE_AUTH_KEY', 'put a long random string here');
define('LOGGED_IN_KEY', 'put a long random string here');
define('NONCE_KEY', 'put a long random string here');
define('AUTH_SALT', 'put a long random string here');
define('SECURE_AUTH_SALT', 'put a long random string here');
define('LOGGED_IN_SALT', 'put a long random string here');
define('NONCE_SALT', 'put a long random string here');A recent case that hit all three of the top causes at once
A client running a busy news site on Cloudways with Cloudflare in front kept losing editor sessions every 10 to 15 minutes. Three editors, all logged out constantly, all losing draft content. I ran the diagnosis in the order above and found three separate causes stacked on top of each other.
First, Settings > General had the site as https://example.com and the CDN was serving www.example.com, so cookies were being set on the wrong host. Second, a Cloudflare Cache Everything page rule from an older CDN setup was caching /wp-admin/, so half the admin responses were served from cache with no user context. Third, Wordfence had IP-based session binding turned on, so the moment an editor's IP shifted (any laptop on hotel Wi-Fi) the session was invalidated.
Fixed the URL to www, added a Cloudflare bypass-cache rule for /wp-admin/*, turned off IP binding in Wordfence. Sessions stopped expiring. Editors got their two-hour writing sprints back. Total fix took 25 minutes once I stopped guessing and worked the checklist in order.
Final checklist
Run through this before you close the tab. If a box is unchecked, the session expired banner will keep coming back.
- Settings > General shows the same URL you type in the browser (protocol, subdomain, and trailing slash all match)
- A single 301 redirect enforces the canonical URL at the server level so admin cookies only exist on one host
- Your cache plugin excludes /wp-admin/, /wp-login.php, /wp-json/, and never caches logged-in users
- Cloudflare (or your CDN) has a Bypass Cache rule for the same admin paths
- No security plugin is binding sessions to a single IP address
- You tested login in a fresh browser profile with all extensions off and confirmed the session survives
- wp-config.php auth keys have not been rotated recently, and if they were, you have logged in fresh after the rotation
- The Remember Me checkbox is available on the login page and works as expected
Complete Fix Checklist
- 1Confirm your site URL and WordPress Address (URL) match exactly in Settings > General, including www vs non-www and http vs https.
- 2Clear every layer of cache: browser, WordPress cache plugin, hosting-level cache (LiteSpeed, Nginx FastCGI, Cloudflare page cache), then log in again.
- 3Exclude wp-admin, wp-login.php, and any URL containing wp- from your caching plugin and CDN rules so logged-in requests are never served from cache.
- 4Check that your browser is accepting third-party cookies for your domain and that no privacy extension is stripping WordPress cookies.
- 5If the site sits behind Cloudflare, disable Rocket Loader on wp-admin and set a Cache Rule that bypasses cache for admin paths.
- 6As a last resort, extend the auth cookie lifetime with a small mu-plugin so 'Remember Me' actually lasts 14 days instead of expiring early.
Quick Tips
- The default WordPress session is 48 hours, or 14 days with 'Remember Me' ticked, if it dies faster than that something upstream is the cause
- Caching a logged-in admin page is the single most common trigger, aggressive cache plugins are the usual culprit
- URL mismatches between siteurl and home cause cookies to be set on one host and rejected on the next request
