A 405 Method Not Allowed response means the server received your request and understood the URL, but the HTTP method you used (GET, POST, PUT, DELETE) is not supported for that endpoint. The server is saying “this URL exists, but you cannot use that method on it.”
This is different from a 404 where the URL does not exist, or a 403 where you do not have permission. With a 405, the resource is there and you may have permission to access it, but the specific method you used is not allowed. A POST to a URL that only accepts GET, or a DELETE to a URL that only accepts POST, both produce a 405.
The response must include an
Allow
header listing which methods the endpoint does support. If you see
Allow: GET, HEAD
in a 405 response, the server is telling you it only accepts GET and HEAD requests at that URL, not the POST or PUT you sent.
HTTP methods explained#
Understanding HTTP methods is essential to diagnosing 405 errors because the error is always about using the wrong method.
GET requests data from the server. Loading a web page, fetching an API response, downloading a file. GET requests should not change anything on the server. They are read-only.
POST sends data to the server to create or process something. Submitting a form, placing a WooCommerce order, uploading a file, saving a WordPress post through the block editor. POST requests change state on the server.
PUT replaces an existing resource with new data. Less common in WordPress, more common in REST APIs. PUT is idempotent, meaning sending the same PUT request multiple times produces the same result.
PATCH partially updates an existing resource. The WordPress REST API uses PATCH for updating posts, pages, and settings. Like PUT, but only sends the fields that changed rather than the entire resource.
DELETE removes a resource. Deleting a post, removing a user, clearing a cache entry.
HEAD is identical to GET but returns only headers, no body. Used by monitoring tools and caching systems to check if a resource exists or has changed without downloading it.
OPTIONS asks the server which methods are supported for a URL. This is the method used in CORS preflight requests, which is why 405 errors and CORS problems are often related.
Common causes in WordPress#
Contact form submissions returning 405
This is one of the most searched 405 scenarios. A visitor fills out a contact form powered by Contact Form 7, WPForms, Gravity Forms, or similar, clicks submit, and gets a 405 error instead of the confirmation message.
The form submits via POST, either to
admin-ajax.php
or to the WordPress REST API depending on the plugin. If something between the browser and WordPress blocks POST requests to that URL, the submission fails with 405.
Common causes:
- A caching layer or CDN is caching the POST endpoint and returning a cached GET response. Most CDNs are configured to pass POST requests through without caching, but misconfigurations happen. Check your CDN or caching plugin’s rules to make sure POST requests to
admin-ajax.phpand/wp-json/are excluded from caching. - A security rule is blocking POST requests to certain URLs. ModSecurity, server-level firewall rules, or a Nginx configuration that restricts methods on specific locations can all produce 405 on form submissions.
- The form action URL is wrong. If the form’s action attribute points to a URL that does not accept POST (a static page, a CDN URL, or a misconfigured permalink), the server returns 405. Inspect the form in your browser’s developer tools and check where it submits to.
WooCommerce checkout failing with 405
WooCommerce checkout relies heavily on POST requests for processing orders, applying coupons, updating the cart, and communicating with payment gateways. A 405 on any of these requests breaks the checkout flow.
The most common cause is a server or CDN configuration that blocks or restricts POST requests to WooCommerce endpoints. WooCommerce uses both
admin-ajax.php
(for legacy AJAX calls) and the WooCommerce REST API (for newer block-based checkout). Both must accept POST requests.
If the 405 only appears on the payment step, the issue may be with the payment gateway callback. Some gateways send POST callbacks to your site to confirm payment. If your server blocks POST to the callback URL, the gateway cannot confirm the transaction.
WordPress REST API returning 405
The WordPress REST API supports multiple methods on the same URL. For example,
/wp-json/wp/v2/posts/123
accepts GET (read the post), PUT/PATCH (update the post), and DELETE (trash the post). If the server is configured to only allow GET on that URL pattern, any attempt to save, update, or delete through the REST API returns 405.
This directly causes the “Updating failed” or “Publishing failed” error in the block editor, because the editor saves content via POST/PUT to the REST API. If you see 405 in the browser’s Network tab when clicking Update or Publish, the server is blocking the write method.
XML-RPC blocked with wrong status code
Some server configurations block
xmlrpc.php
by returning 405 instead of 403. This is functionally fine for security purposes (blocking XML-RPC access is generally recommended), but it can cause confusion if a legitimate service like Jetpack or the WordPress mobile app depends on XML-RPC and you see 405 instead of a more descriptive error.
If you intentionally blocked XML-RPC and are seeing 405, that is working as intended. If you need XML-RPC for a specific service, you need to allow POST requests to
xmlrpc.php
from the IPs that service uses.
Common causes in Nginx#
Nginx is a frequent source of 405 errors because its default behavior for static files is to reject any method other than GET and HEAD. If Nginx is handling a request that should be passed to PHP but is instead treating it as a static file request, POST and other methods return 405.
Static file handling rejecting POST
If Nginx serves a URL directly as a static file instead of passing it to PHP-FPM, POST requests to that URL return 405. This happens when a
location
block matches the URL before the PHP handler does:
# This serves everything in /forms/ as static files
# POST requests to /forms/submit will return 405
location /forms/ {
root /var/www/html;
}
The fix is to make sure URLs that need PHP processing are passed to PHP-FPM:
location /forms/ {
try_files $uri $uri/ /index.php?$args;
}
limit_except blocking methods
Nginx’s
limit_except
directive restricts which HTTP methods are allowed in a location block:
location /api/ {
limit_except GET {
deny all;
}
proxy_pass http://backend;
}
This allows GET requests to everyone but denies all other methods. If your API endpoint needs to accept POST, PUT, or DELETE, adjust the
limit_except
block:
location /api/ {
limit_except GET POST PUT DELETE {
deny all;
}
proxy_pass http://backend;
}
error_page 405 workaround
A common workaround for Nginx returning 405 on POST requests to static resources is:
error_page 405 =200 $uri;
This converts the 405 response to a 200 and serves the static file anyway. This is a hack, not a fix. It hides the real problem, which is that Nginx is handling a request that should go to a dynamic backend. Use this only as a temporary measure while you fix the actual routing.
Proxy configuration missing methods
When Nginx proxies requests to a backend application, the proxy configuration must pass the original HTTP method through. This is the default behavior, but custom configurations can interfere:
location /api/ {
proxy_pass http://backend;
proxy_method GET; # This forces all requests to GET, breaking POST/PUT/DELETE
}
Remove any
proxy_method
directive unless you have a specific reason to override the client’s method.
405 and CORS preflight requests#
Cross-Origin Resource Sharing (CORS) is a common source of 405 errors that gets misdiagnosed. When a browser makes a cross-origin request that is not “simple” (anything with custom headers, non-standard content types, or methods other than GET/POST), it first sends a preflight request using the OPTIONS method.
If the server does not handle OPTIONS requests for that URL, it returns 405. The browser interprets this as a CORS failure and blocks the actual request. The error in the browser console may say “CORS policy” but the underlying cause is a 405 on the OPTIONS preflight.
The fix is to make sure the server responds to OPTIONS requests with the appropriate CORS headers:
location /api/ {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, X-WP-Nonce';
add_header 'Access-Control-Max-Age' 86400;
return 204;
}
proxy_pass http://backend;
}
Be specific with
Access-Control-Allow-Origin
in production. Using
*
allows any origin, which may not be appropriate for authenticated endpoints.
Diagnosing a 405#
Check the response headers
curl -I -X POST https://example.com/api/endpoint
The
-X POST
flag sends a POST request. The
-I
flag shows only the response headers. Look for:
- The status code (405)
- The
Allowheader, which tells you which methods are accepted - The
Serverheader, which tells you whether Nginx, Apache, or the application returned the 405
Test with different methods
# Test GET
curl -I https://example.com/api/endpoint
# Test POST
curl -I -X POST https://example.com/api/endpoint
# Test OPTIONS (CORS preflight)
curl -I -X OPTIONS https://example.com/api/endpoint
If GET returns 200 but POST returns 405, the server is configured to reject POST for that URL. The
Allow
header in the 405 response confirms this.
Check Nginx access and error logs
grep " 405 " /var/log/nginx/access.log | tail -20
grep "not allowed" /var/log/nginx/error.log | tail -20
The access log shows which URLs are returning 405 and which method was used. The error log may show additional context about why the method was rejected.
Check in browser developer tools
For WordPress and WooCommerce 405 errors, open the browser’s developer tools (F12), go to the Network tab, and reproduce the error. Click the failed request and check:
- The request method (POST, PUT, DELETE)
- The request URL (is it going to the right endpoint?)
- The response status (405)
- The response headers (look for
Allow) - Whether an OPTIONS preflight was sent before the actual request
Quick reference#
| Symptom | Likely cause | Fix |
|---|---|---|
| Contact form returns 405 | CDN caching POST, or server blocking POST to ajax URL | Exclude
admin-ajax.php
from cache, check server rules |
| WooCommerce checkout 405 | POST blocked to WooCommerce endpoints | Check CDN/firewall rules for WooCommerce URLs |
| Block editor “Updating failed” with 405 | Server blocking PUT/POST to REST API | Check Nginx config for method restrictions on
/wp-json/
|
| 405 on static file POST | Nginx treating dynamic URL as static | Fix
try_files
to route to PHP-FPM |
| CORS error with underlying 405 | Server not handling OPTIONS preflight | Add OPTIONS handler with CORS headers |
| API returning 405 | Wrong HTTP method for the endpoint | Check API docs for correct method, check
Allow
header |
For other HTTP error codes in WordPress, see How to fix the most common WordPress errors. For Nginx-specific 400 errors, see How to fix 400 bad request in Nginx. For 404 errors, see How to fix 404 errors in Nginx.