405 Method Not Allowed Error: Causes and How to Fix It

· 7 min read · 16 views · Getwebup

The short answer

A 405 Method Not Allowed means the URL exists but rejects the HTTP method you used - usually a POST to a URL that only accepts GET. It is not a 403, which refuses you entirely. Read the response Allow header to see which methods the resource accepts, then check the form action, .htaccess LIMIT directives, and any WAF rule blocking the method.

A 405 Method Not Allowed error means the server understood exactly what you were asking for, and refused to let you ask for it that way. It's not a missing page (that's a 404) and it's not a permissions problem in the usual sense (that's a 403) - it's a server, plugin, or firewall rule saying "this URL doesn't accept that HTTP method." Here's how to find which layer is doing the blocking and fix it.

What a 405 actually means

Every HTTP request has a method attached to it - GET, POST, PUT, DELETE, HEAD, OPTIONS. A 405 shows up when a client sends a method the target URL isn't configured to accept. Browsers usually only send GET (loading a page) and POST (submitting a form), so when you see this error as a regular visitor, something unusual is happening: a form is posting to the wrong place, a cached page is intercepting a POST, or a security rule is stripping methods it doesn't like.

If you're a developer hitting a REST API or webhook, it's more straightforward - you sent a PUT or DELETE to an endpoint that's only wired up for GET and POST, or a proxy in front of it is filtering methods before your request even reaches the app.

Step 1: Confirm which method and which URL

Before touching any config, get the exact request. Open your browser's DevTools Network tab, reproduce the error, and click the failed request. Note:

  • The exact URL that returned 405
  • The request method (GET, POST, PUT, DELETE, OPTIONS)
  • The response headers - look for an Allow header, which tells you which methods the server will accept
  • Which server is answering - check the Server header (nginx, Apache/LiteSpeed, cloudflare) so you know where to start looking

You can also reproduce it from the command line, which strips out browser extensions and cache as suspects:

curl -I -X POST https://example.com/wp-json/wp/v2/posts

If curl gives you the same 405 that the browser does, the problem is server-side, not a stale asset or extension.

Common cause 1: A form posting to the wrong URL

This is the single most common cause on WordPress and WooCommerce sites. A contact form, checkout page, or login form is set to POST to a URL that either doesn't exist as a script endpoint or has been rewritten by a redirect. Classic triggers:

  • A page was moved and a 301 redirect now points the form's action URL somewhere that only accepts GET
  • The site was migrated from HTTP to HTTPS (or old domain to new) and the form still hardcodes the old URL, which redirects and drops the POST body along the way
  • A caching plugin or CDN served a cached version of a page that should have processed the POST dynamically

Fix: Check the form's action attribute against the live URL. If a redirect is involved, most redirects (301/302) will actually re-send a GET on the second hop unless the server does a 307/308 - so any form pointed at a redirecting URL is a landmine. Update the form to point directly at the final URL instead of relying on the redirect.

Common cause 2: Apache/.htaccess LIMIT directives

If you or a security plugin added a <Limit> or <LimitExcept> block to .htaccess, it can silently restrict a directory to only GET and HEAD. This shows up a lot after hardening guides that lock down uploads folders.

<LimitExcept GET HEAD>
  Order deny,allow
  Deny from all
</LimitExcept>

That block returns 405/403 for anything else hitting that directory, including legitimate POST requests from a plugin's AJAX handler if it happens to live in the restricted path. Comment the block out temporarily to confirm, then rewrite it to allow the specific method your app actually needs.

Common cause 3: Nginx explicitly returning 405

On a VPS running Nginx (or Nginx in front of Apache/PHP-FPM), someone may have added a method allowlist like this:

if ($request_method !~ ^(GET|HEAD|POST)$) {
    return 405;
}

This is common in hardened server blocks meant to block PUT/DELETE probing, but it also blocks legitimate PUT/DELETE calls your own REST API or app needs - which matters a lot if you're running a Node.js app or a WordPress site using the block editor's autosave, since both rely on methods beyond plain GET/POST. Search your site's config for return 405 and request_method:

grep -rn "request_method\|return 405" /etc/nginx/

If you find a match and the blocked method is one your app legitimately needs, add it to the allowlist and reload Nginx with nginx -t && systemctl reload nginx.

Common cause 4: Cloudflare or a WAF blocking the method

If your site sits behind Cloudflare or another WAF/CDN, check two things in the dashboard:

  • Firewall/WAF rules - a custom rule matching on http.request.method may be blocking or challenging PUT/DELETE/PATCH requests meant for a REST API
  • Page Rules or Cache Rules - if a rule is caching a URL that should be dynamic (e.g. an API endpoint or checkout path), Cloudflare can serve a cached response for a method it never should have cached, producing odd 405s intermittently

Fix: In Cloudflare, go to Security > WAF > Custom rules and check for anything referencing HTTP methods. For caching, make sure API and form-submission paths are excluded via a Cache Rule set to "Bypass cache."

WordPress REST API and Gutenberg-specific 405s

If the 405 shows up specifically when saving a post, uploading media in the block editor, or hitting /wp-json/ URLs, the REST API route itself may only be registered for certain methods. This happens with custom endpoints registered like this:

register_rest_route('myplugin/v1', '/items', array(
  'methods' => 'GET',
  'callback' => 'my_callback',
));

If a plugin's JavaScript then tries to POST or PUT to that same route, WordPress correctly returns 405 because the route was never registered for that method. This is a plugin/theme code bug, not a server misconfiguration - check for a plugin update, or if it's custom code, add the missing method to the methods array (WordPress accepts an array like array('GET', 'POST')).

Also confirm your permalink structure isn't set to "Plain" (Settings > Permalinks) - the REST API relies on pretty permalinks to route correctly, and a plain structure can produce inconsistent method errors on some setups.

Quick diagnostic table

SymptomLikely layerWhere to look
Only happens on one contact/checkout formApplicationForm's action URL and any redirects on it
Whole folder returns 405 for anything but browsingApache.htaccess Limit/LimitExcept blocks
REST/API calls with PUT, DELETE, PATCH failNginx or WAFNginx request_method checks, Cloudflare WAF rules
Only in the block editor / Gutenberg / ElementorWordPress pluginPlugin's register_rest_route method list
Intermittent, works then failsCDN cacheCloudflare Cache Rules on that path

Prevention checklist

  • Never point a form's action at a URL that redirects - use the final destination directly
  • When hardening .htaccess or Nginx configs, list every method your app actually uses (including OPTIONS for CORS preflight) before locking things down
  • Exclude API and form-submission paths from CDN/page caching explicitly, don't rely on defaults
  • Test plugin and theme updates on a staging site before pushing to production, especially anything touching custom REST routes
  • Keep permalinks on a pretty structure (not "Plain") so WordPress's REST API routing behaves predictably

Questions people actually ask