How to Fix “403 Forbidden” on WordPress Pages, Forms or Admin Actions
A 403 means something refused the request on purpose. Read the headers and body to find which layer sent it, then fix that layer without switching off security.
The layout is a mess, styles are missing or buttons and menus do not work.
Do this first
Diagnose it
The way a page breaks points to the cause. Note which pattern you have before you start purging and toggling.
| What you see | What it points to |
|---|---|
| Plain text, blue links, Times New Roman, the menu as a bullet list | The main stylesheet is not loading at all. |
| Layout mostly right, but menus, sliders, tabs or popups do not respond | A JavaScript error stops scripts from running. |
| Squares or blank spaces instead of icons | The icon font file is blocked, often by CORS, or missing. |
| Broken for visitors, fine when logged in (or the reverse) | A cached copy of the page is out of date. |
| Broken on phones only | A responsive layout or separate mobile cache problem. |
| Images missing but text styled | Wrong upload URLs, hotlink protection or a CDN fault. |
| A shared link on Facebook, LinkedIn or in a chat app shows the wrong picture or none | Missing or wrong Open Graph tags, or the platform cached an old preview. See wrong image when sharing a link. |
The browser console (F12, then the Console tab) usually names the cause. The messages you are most likely to see:
Refused to apply style from '...css' because its MIME type ('text/html') is not a supported stylesheet MIME type: the CSS address returned an HTML page instead, usually a 404 page, a login page or a firewall block.Mixed Content: The page at 'https://...' was loaded over HTTPS, but requested an insecure stylesheet 'http://...'. This request has been blocked: an old http:// address.Access to font at '...' from origin '...' has been blocked by CORS policy: the font sits on another domain that does not allow your site to use it.Uncaught ReferenceError: jQuery is not defined: a script ran before jQuery loaded, nearly always from deferring or combining JavaScript.Refused to load ... because it violates the following Content Security Policy directive: a security header is blocking the file.1. List the stylesheets the page asks for.
curl -s https://example.com/ | grep -oE 'href="[^"]+\.css[^"]*"'
Run it on your own computer’s terminal, replacing example.com with your domain. It prints the address of each CSS file in the page. Look for addresses on an old domain, a staging site, or starting with http://.
2. Test one of those files.
curl -sI CSS_FILE_URL | grep -iE '^(HTTP|content-type|content-length|server|cf-cache-status)'
Run it on your own computer. CSS_FILE_URL is one full address from check 1, ideally from your theme or page builder. Good: 200, content-type: text/css and a content-length above 0. Bad: 404 (the file is gone), 403 (a firewall or hotlink rule blocks it), content-type: text/html (an error page served in its place), or content-length: 0 (the file was written empty).
3. Compare logged in and logged out. Open the page in a private window with extensions disabled, next to your normal logged-in window. If only the private window is broken, a page cache is serving an old copy. If only your normal window is broken, suspect a browser extension.
4. See what changed in WordPress.
wp plugin list --fields=name,status,version,update_version
wp theme list --status=active --fields=name,version
Run these in an SSH terminal inside the site’s folder (the one with wp-config.php). --fields limits the columns shown. Compare versions against when the problem started: an update to the theme, builder or an optimization plugin on that day is your lead.
jQuery is not defined or $ is not a function in the console, starting after a change to defer, delay or combine settings. Fix: exclude jQuery and the broken script from deferral, or switch that feature off.http://. Fix: a search and replace on the database (dry run first), then regenerate builder CSS.text/html responses for .css, .js or font files. Fix: allow those file types for your own domain and any CDN hostname.content-length: 0, or regenerating does nothing. A full disk or wrong folder ownership stops the builder writing files. Fix: free disk space, and ask your host to correct ownership of wp-content/uploads.Did this fix it?
Still stuck? Start again from what you can see in the Emergency Room.
The full fix
A 403 means something refused the request on purpose. Read the headers and body to find which layer sent it, then fix that layer without switching off security.
You see the new page, visitors see the old one, or the reverse. Read the cache headers to find which layer served it, then purge in the right order.
Blocks flagged as invalid or “Your site doesn’t include support” after a theme switch, plugin removal or update. Recover them without losing content.
Place order spins forever or shows “There was an error processing your order”. Read the checkout request in the Network tab, check the logs, then fix the gateway, cache or script.
Products vanish from the cart, the mini cart shows the wrong count, or checkout says your session has expired. Trace the session cookie, then fix cache rules and domains.
After a WooCommerce update the store looks wrong, orders vanish from a report or an extension errors. Finish the database update, fix template overrides and HPOS, or roll back.
Move WordPress without a migration plugin: dump the database, copy the files, import, run a safe search-replace, test through your hosts file, then switch DNS.
A full staging push overwrites every order, customer, review and form entry that arrived on live since you cloned it. Here is how to deploy changes and keep that data.
Move a WordPress site to a newer PHP version without downtime: check support dates, scan plugins for incompatible code, test on staging, switch per site and roll back fast.
Uploads fail with upload_max_filesize, “exceeds the maximum upload size” or 413 errors. Find which layer set the limit (PHP, web server, WAF or CDN) and raise the right one.
Media uploads fail with an HTTP error, an image processing error or a file type refusal. Read the log, then fix memory, Imagick, file types or folder permissions.
You click Save Menu and the last items vanish or never stick. Find out whether PHP is cutting off the form, a script is failing, or the save is timing out, and fix it.
Search the field manual
Or jump straight to a symptom
Press / to search from any page, Esc to close