403 Forbidden Error: Causes and How to Fix It
A 403 Forbidden error means the server understood your request and flat-out refused it — this isn't a missing-page problem like a 404, it's a permission problem. The good news: there are really only a handful of things that cause it, and most of them take under ten minutes to fix once you know where to look.
Symptom: what a 403 actually looks like
A 403 shows up a few different ways depending on what's serving your site:
- A plain white page with "403 Forbidden" and nothing else — usually straight from Apache or Nginx.
- "Access Denied - You don't have permission to access this resource" with a server signature at the bottom.
- A branded error page from Cloudflare or another CDN, sometimes with a Ray ID.
- The homepage loads fine but one folder or file returns 403 while everything else works.
- The site worked yesterday and started throwing 403s today with no code changes on your end.
The exact wording matters less than where it's coming from. A 403 with a server signature (like Apache/2.4.58) is coming from your hosting stack. A 403 with a CDN's own branding is coming from a layer in front of your server — different fix entirely.
Cause 1: no index file and directory listing is off
If you open a folder URL (like yourdomain.com/uploads/) instead of a specific page, and there's no index.html or index.php inside it, the server has nothing to serve. With directory listing disabled — which is the sane default — you get a 403 instead of a file list.
Fix: either drop a blank index.html into the folder, or just don't link to bare directory URLs. This one is rarely the "real" bug; it's usually a stray link or a misconfigured redirect pointing at a folder instead of a page.
Cause 2: an .htaccess Deny rule or IP block
Apache's .htaccess can block specific IPs, referrers, or user agents. If someone (a past developer, a security plugin, an automated hardening script) added a Deny from all or an <Files> block that's too broad, it can catch legitimate visitors too.
Check the file at the root of your site:
cat public_html/.htaccess
Look for lines like:
Order allow,deny
Deny from all
<Files "wp-config.php">
Order allow,deny
Deny from all
</Files>
The first blocks everything from that folder down. The second is normally fine (it's protecting a sensitive file) — but if it's wrapping something it shouldn't, like an entire /wp-content/uploads/ block, that's your problem. Comment out the suspicious block with a #, reload the page, and see if the 403 clears.
Cause 3: ModSecurity or another WAF rule
If you're on a cPanel server, ModSecurity inspects requests before they reach your app, and it will happily 403 a request that looks like an attack even when it's a real customer clicking a real button — long query strings, certain special characters in a URL, or a plugin doing something unusual with headers can all trip a rule.
In cPanel, go to Metrics → Errors or check /usr/local/apache/logs/modsec_audit.log if you have SSH access. You're looking for a line with an id field, something like:
ModSecurity: Access denied with code 403 (phase 2).
Matched "Operator `Rx' ... [id "981173"] [msg "SQL Injection Attack..."]
That ID is what you need. Don't disable ModSecurity entirely — instead, whitelist that one rule for that one path in WHM under ModSecurity Tools, or ask your host to do it. Blanket-disabling the whole ruleset just to fix one false positive trades a minor annoyance for a real security gap.
Cause 4: hotlink protection or referrer blocking
If it's only images or specific file types returning 403, and only when loaded from certain places (or not at all, even on your own site), hotlink protection is a likely suspect. It's meant to stop other sites from embedding your images directly, but an overly strict rule can end up blocking your own CDN, a staging domain, or even Google's image cache.
In cPanel, check Security → Hotlink Protection. If it's enabled, make sure your own domain (with and without www), any CDN hostname you use, and any staging subdomains are all in the allowed list.
Cause 5: the server is blocking your IP outright
Too many failed login attempts, a scan that looked like brute-forcing, or a security tool flagging unusual traffic can get an IP added to a deny list. This is common right after a WordPress brute-force attempt or a misconfigured monitoring tool that hammers a URL.
In WHM, check ConfigServer Security & Firewall (CSF) under Firewall Temporary & Permanent Blocks. In cPanel directly, check Security → IP Blocker. Search for your own IP (get it from whatismyip.com style checkers) and remove the block if it's there.
Cause 6: a CDN or reverse proxy in front of your server
If the 403 page has Cloudflare's or another CDN's branding rather than your server's, the block is happening before the request even reaches your host. Common triggers:
- A Cloudflare firewall rule or "Under Attack Mode" flagging legitimate visitors as bots.
- A WAF managed ruleset blocking a specific path (login pages and admin areas get flagged often).
- Origin server access rules that only allow traffic from the CDN's IP ranges, and something is bypassing the CDN.
Check the CDN's dashboard — Cloudflare's Security → Events log will show exactly which rule fired and for which request. Nine times out of ten it's a rule that's too aggressive for a specific URL pattern (like /wp-login.php or a custom API endpoint), and you can add an exception rather than turning the whole WAF off.
Cause 7: file or folder permissions are wrong
Less common than it used to be, but still worth a quick check, especially after a migration or a zip extraction that reset permissions. Web servers need at least execute permission on every folder in a path and read permission on the file itself.
Standard values for shared/cPanel hosting:
| Item | Correct permission |
|---|---|
| Folders | 755 |
| Files | 644 |
| wp-config.php / similar config files | 640 or 600 |
Via SSH, you can reset an entire site in one pass:
find /home/username/public_html -type d -exec chmod 755 {} \;
find /home/username/public_html -type f -exec chmod 644 {} \;
Run that only from the correct account's home directory — it touches every file underneath, so double-check the path before hitting enter.
How to narrow it down fast
- Note whether the 403 page has your server's signature, a CDN's branding, or nothing at all — that tells you which layer to check first.
- Check if it's the whole site or one specific URL/file type — narrow scope points at .htaccess rules, hotlink protection, or ModSecurity, not a global block.
- Check the error log (cPanel → Metrics → Errors, or your CDN's security log) before touching any config — it usually names the exact rule.
- Test from a different network (mobile data, a VPN) to rule out an IP-specific block.
Prevention
- Keep a copy of your working
.htaccesssomewhere outsidepublic_htmlso you can diff it after a security plugin or migration touches it. - When a security tool (ModSecurity, a WAF, a hardening plugin) blocks something, whitelist the specific rule or path — don't disable the tool.
- Review Hotlink Protection and IP Blocker settings after any big traffic spike or after installing a new security plugin, since those are the two settings most often turned on and then forgotten.
- If you're behind Cloudflare, set your firewall rules to "Log" for a day before switching them to "Block" on anything new — you'll catch false positives before they hit real visitors.
Frequently asked questions
Is a 403 error the same as a 404 error?
No. A 404 means the page doesn't exist. A 403 means the server found something at that URL but is refusing to show it to you - a permission or access-control problem, not a missing-page problem.
Why am I getting a 403 error only on my WordPress admin login page?
This is almost always a WAF or ModSecurity rule, an .htaccess IP restriction someone added for security, or a security plugin's brute-force protection flagging your IP after a few failed logins. Check your host's ModSecurity/WAF logs first - they'll usually name the exact rule that fired.
Should I just disable ModSecurity to get rid of a 403?
No. Disabling it removes real protection for your whole site to fix one false positive. Find the rule ID in the ModSecurity log and whitelist that specific rule for that specific path instead.
I fixed the permissions but I'm still getting a 403 - what else could it be?
Permissions are only one of several causes. Check .htaccess for Deny rules, look at your host's ModSecurity/error logs, check Hotlink Protection and IP Blocker in cPanel, and if you're behind Cloudflare or another CDN, check its security event log too - the block may be happening before the request even reaches your server.
Can a CDN like Cloudflare cause a 403 even if my server is fine?
Yes. If the 403 page shows the CDN's own branding instead of your server's error page, the block is happening at the CDN layer - usually a firewall rule, a managed WAF ruleset, or bot-fight mode flagging a legitimate visitor. Check the CDN's security/firewall event log to see which rule matched.