You log in to WordPress, the form accepts your password, the dashboard URL loads, and instead of a screen you see a near-empty page with one line of text: Sorry, you are not allowed to access this page. The login worked. Something else rejected you a fraction of a second later.
What this message actually means
The text comes from wp_die(), called by an admin screen after current_user_can() returned false for the capability that screen requires. WordPress is not saying it does not know you. It is saying it knows you, looked up your role, mapped that role to a set of capabilities, and decided your account does not hold the one needed for this URL. The mechanism is by design and documented in the WordPress roles and capabilities reference: every admin screen has a required capability and every account has a role that either holds it or does not. For the full reference of which role grants which capability, see WordPress user roles and permissions.
In plain language: your account was let through the door, the hallway map was checked, and the door to the room you tried to enter is the wrong room for you. The site is not broken. The capability check did exactly what it was designed to do, which is also why this is a different problem from "I cannot log in": the login pipeline succeeded, cookies arrived, WordPress knows who you are, and the block sits one step further in, at the capability check.
How the WordPress capability system actually works
WordPress separates two concepts that look the same from the outside but behave very differently inside the request: roles and capabilities. The official roles and capabilities reference is the canonical description, and knowing the rough shape is what lets the rest of this article make sense.
A role is a label attached to a user account: administrator, editor, author, contributor, subscriber, plus super_admin on multisite. WordPress ships six predefined roles and lets plugins register more. The role itself does almost nothing on its own.
A capability is the unit the application actually checks. Names like manage_options, activate_plugins, edit_others_posts, and read are capabilities. Every admin screen, every REST endpoint, and every privileged action declares the capability it requires, and WordPress decides whether to serve it by asking: does this user have this capability, yes or no? The mapping from role to capability set lives in the database, in the option <prefix>user_roles, and on each user in the <prefix>capabilities row of wp_usermeta.
When code calls current_user_can('manage_options'), WordPress is not asking "is this user an administrator". It is asking "does this user, regardless of label, hold this specific capability". The official documentation is explicit on this point: checking against roles directly "is discouraged as it may produce unreliable results", because two accounts with the same role can hold different capabilities after a plugin has touched them. A subscriber can be granted manage_options by a plugin and immediately reach the Settings screen. An administrator can have manage_options stripped and immediately stop reaching it.
That decoupling is the entire reason the message exists as its own response. WordPress does not need to know why a capability is missing in order to refuse the request. It refuses, says so, and stops. Explicit refusal is auditable: a silent redirect would look identical to a session bug and would burn hours on the wrong diagnosis, which is exactly why the no access to wp-admin without an error article exists for the silent variant of this problem.
What this message is NOT
This is the routing block that prevents most wasted debugging time.
- It is not a login failure. You are authenticated. The login pipeline completed successfully, your password was accepted, and the cookies were issued. If credentials had been wrong, you would never have reached
wp-admin/at all. For login failures with visible error text, start at why you cannot log in to WordPress. - It is not a 403 Forbidden. A 403 is a web-server denial that happens before WordPress runs. The
Sorry, you are not allowed to access this pagemessage is generated by WordPress itself, after it loaded and recognised you. The mechanisms are completely different and so are the fixes. If the dashboard or login URL returns a 403 status code from the server with no WordPress branding, read 403 Forbidden on wp-admin. - It is not a password problem. The capability check runs long after the password check. If your password had been wrong, the login form would have rejected you. By the time you can see this text, the password layer has already approved you.
- It is not a cookie or session problem. A broken cookie or session sends you back to the login screen with no message at all, which is the silent variant covered in no access to wp-admin without an error. The capability message means the cookies arrived, WordPress used them to load your account, and only then refused the screen.
- It is not a WordPress bug. The error is the system working as designed. The bug, when there is one, is in the role definition, the plugin that rewrote it, the migration that broke the lookup, or the cache layer that handed you the wrong session. Those are the five causes covered below.
Common causes, ordered by likelihood
Five mechanisms account for almost every instance of this message on a WordPress 6.7 site. The order below reflects what I see most often.
- Your user role was downgraded or the capability was stripped. A staging sync, a restored database backup, or a manual edit reset your account from
administratorto a lower role, or removed the specific capability the screen needs. WordPress validates the password fine and then refuses the screen. - A plugin rewrote your role on activation. Membership, LMS, and custom-role plugins call
add_role()andremove_cap()on activation and update. A bad upgrade or a misconfigured plugin can rewrite theadministratorrole itself, dropping capabilities that every other admin on the site loses too. - The table prefix in
wp-config.phpdoes not match the prefix on the database tables. WordPress reads roles from the option<prefix>user_rolesand capabilities from<prefix>capabilitiesinwp_usermeta. After a migration that changed prefixes, the lookup returns nothing and your account ends up with no capabilities at all. The mechanism is documented in the WP_Roles class reference. - The auth cookie is being served to the wrong account. A page cache or a reverse proxy that does not vary on the
wordpress_logged_in_[hash]cookie can hand you a cached admin screen for someone with a lower role, then redirect you mid-request to a screen your real account cannot see. - A theme or plugin is calling
current_user_can()against a capability that no longer exists. A custom capability gets removed (often by a plugin update) but a different plugin still checks for it on the screen you visit. The check returnsfalseand WordPress kills the request.
Diagnose which cause applies
Run these checks in order. They are non-destructive and they isolate the cause before you change anything.
Check 1: confirm the message comes from inside WordPress. Open the failing URL and look at the actual page. If you see Sorry, you are not allowed to access this page. rendered on the WordPress error screen (white background, simple text, no host branding), the request reached PHP. If you see a Cloudflare, Sucuri, or Wordfence block page instead, the layer in front of WordPress rejected you and you need 403 Forbidden on wp-admin. You will know it worked when: you can confirm the page is the WordPress wp_die() screen and not a third-party block page.
Check 2: read your role from wp_usermeta. Open phpMyAdmin (or any database client) and run:
-- Replace wp_ with your actual table prefix if different
SELECT user_id, meta_value
FROM wp_usermeta
WHERE meta_key = 'wp_capabilities'
AND user_id = 1;
A working administrator returns the serialized string a:1:{s:13:"administrator";s:1:"1";}. Anything else (a different role, an empty array, or no row at all) is your answer for cause 1. You will know it worked when: you can quote the exact meta_value for your account.
Check 3: confirm the table prefix matches. Open wp-config.php in your hosting panel's file manager (or download it via SFTP) and read the $table_prefix line. Then in phpMyAdmin look at the actual table names. The prefix in the file must match the prefix on the tables exactly, including case. If wp-config.php says wp_ but the tables are wpx7_users and wpx7_usermeta, that mismatch is cause 3 and the role lookup will return nothing for every user. You will know it worked when: the $table_prefix value and the database table names start with the same string.
Check 4: try a private window with a fresh login. Open an incognito window, log in from scratch, and visit the failing screen. If the error disappears, you were being served a cached response written for a different account or a stale session. That is cause 4. If the error is identical from a clean session, the cause is in WordPress itself, not in the cache layer. You will know it worked when: you can say either "the private window works" or "the error is the same in every window".
Check 5: deactivate plugins from the file system. Using your hosting panel's file manager (or an SFTP client), rename wp-content/plugins to wp-content/plugins_off, log in, and visit the failing screen. If the error disappears, a plugin is the source. Rename the folder back, then re-enable plugins one at a time from the dashboard until the message returns. This is the only safe way to test cause 2 and cause 5 without admin access. You will know it worked when: you can name the specific plugin whose activation reproduces the error.
Solutions, per cause
Cause 1 fix: restore the role on the affected account
If Check 2 showed the wrong value, write the correct one back. From phpMyAdmin, edit the row and set meta_value to:
a:1:{s:13:"administrator";s:1:"1";}
If you prefer the command line and have WP-CLI installed, the equivalent is one command:
wp user set-role <user_id> administrator
If your account row in wp_usermeta does not exist at all, recreate it. Insert a row with user_id set to your user ID, meta_key set to wp_capabilities, and meta_value set to the serialized string above. Then add a second row with meta_key set to wp_user_level and meta_value set to 10, which is the legacy admin level still expected by some plugins.
Verification: log out, log back in, and load the screen that returned the error. You will know it worked when the dashboard renders normally and current_user_can('manage_options') would return true for your account.
Cause 2 fix: rebuild the role definitions
When a plugin has rewritten the administrator role itself, fixing one user is not enough; the role definition needs to be restored.
Using your hosting panel's file manager (or an SFTP client), rename the offending plugin's folder under wp-content/plugins to deactivate it. Then log in and visit Tools > Site Health. The dashboard load forces WordPress to re-check role definitions. If the administrator role is missing entirely, you can recreate it with the default capability set documented on WordPress.org's roles and capabilities reference.
WP-CLI alternative: if you have SSH access, you can reset the role in one command:
wp role reset administrator
Verification: every administrator on the site can reach the failing screen without the message, not just yours.
Cause 3 fix: align the table prefix
If Check 3 found a mismatch, decide whether to change the prefix in the file or rename the tables. Changing the file is safer when you know the tables are correct (for example, after a migration where you copied the database with a different prefix). Open wp-config.php in your hosting panel's file manager (or download it via SFTP) and edit the prefix line:
$table_prefix = 'wpx7_';
The trailing underscore is required and the value must match exactly. There is nothing else to update on the WordPress side: WordPress reads the prefix from wp-config.php on every request and rebuilds the option name dynamically.
If the tables are wrong instead, rename them to match the prefix in the file. This is a write operation on every WordPress table at once, so back up the database first and run it during a maintenance window. After rename, you also need to update the two rows inside the database that hard-code the prefix: <prefix>options row where option_name = '<prefix>user_roles', and every row in <prefix>usermeta where meta_key starts with the old prefix. The WordPress Codex on changing the table prefix lists the exact rows to update.
Verification: log in, hit the failing screen, and confirm the message is gone. Then run a query against <prefix>options for option_name = '<prefix>user_roles' and confirm one row exists with a populated value.
Cause 4 fix: bypass the cache for logged-in users
If the private window in Check 4 worked but a normal browser still fails, your cache is serving a response cached for a different account. Almost every page cache supports a "do not cache logged-in users" rule keyed on the wordpress_logged_in_[hash] cookie. Enable it.
For WP Rocket, LiteSpeed Cache, W3 Total Cache, and most managed-host caches, the option is on by default but can be disabled accidentally during configuration. Check your cache plugin's settings in wp-admin to confirm it is enabled.
If you have SSH access and use nginx FastCGI cache, the rule lives in the server block:
set $skip_cache 0;
if ($http_cookie ~* "wordpress_logged_in") {
set $skip_cache 1;
}
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
Then purge the cache fully. A partial purge will leave the bad entries in place.
Verification: the failing screen loads correctly in a non-private browser session, and a request to the same URL with curl -I no longer returns a X-Cache: HIT header for an authenticated cookie.
Cause 5 fix: find the missing capability
If Check 5 isolated the error to a specific plugin, the fastest path is the plugin's own settings. Look for an option labelled "rebuild capabilities", "reset roles", or similar. Membership, LMS, and role editor plugins typically have one because they know their own activation can leave roles in inconsistent states.
If that does not exist, install the User Role Editor plugin on a staging copy and inspect the capabilities of the role the failing screen requires. Compare against the default set on WordPress.org's roles and capabilities reference for that role. The missing capability is almost always the one the failing screen passes to current_user_can(). Add it back from the role editor and test.
Verification: the screen loads, and removing User Role Editor again does not bring the error back, since the capability is now persisted in the database.
When to escalate
If twenty minutes of diagnosis have not pinpointed the cause, hand the incident to your host or a developer. The faster you can hand over the following list, the faster they can act:
- The exact URL that returns the message.
- The exact text on the screen, and a screenshot showing whether it is the WordPress
wp_die()screen or a third-party block page. - The output of Check 2: the
meta_valueofwp_capabilitiesfor the affected user, copy-pasted. - The output of Check 3: the
$table_prefixvalue fromwp-config.phpand the actual table names from the database. - Whether a private window reproduces the error.
- Whether renaming
wp-content/pluginsmakes the error disappear. - The list of plugins, themes, and core changes made in the 48 hours before the error first appeared.
- WordPress version, PHP version, and the host name.
If you suspect a security incident rather than a configuration problem, treat it that way. Reset every administrator password, audit <prefix>users for unfamiliar accounts, and look at the 403 Forbidden in WordPress article before you change anything else, since intrusion attempts often surface there first.
How to prevent it from coming back
Three habits keep this message rare on a healthy WordPress site:
- Always test plugin updates on staging first when the plugin manages roles or capabilities. Membership, LMS, and role editor plugins are the highest-risk class for this message. If you cannot stage, take a database backup right before the update so the rollback is one step.
- Never change the table prefix on a live database without a tested rollback. A prefix change touches every WordPress table at once and breaks role lookup the moment it goes wrong. If you must change it, do the rename, the option row, and the usermeta rows in the same migration.
- Keep your page cache configured to bypass logged-in users. This single rule prevents the cache-induced version of the error and a long list of unrelated session bugs at the same time. Verify it after every cache plugin update.