Aditya Sharma

WordPress 413 Request Entity Too Large: The nginx Default

On this page, 10 sections

A 413 “Request Entity Too Large” on a WordPress upload usually comes from nginx, which rejects any request body over client_max_body_size. The nginx default is 1m. Raise it in the server or location block, then raise the two PHP limits to match.

Three layers can reject the same upload, and each uses a different setting and a different error. If you raise only one, the number WordPress shows you will not match what actually works.

I read the nginx, PHP and Cloudflare documentation and WordPress 7.1.3 source on 11 October 2026, and ran the PHP side locally. I did not run nginx here, so no nginx config below was tested.

The defaults, with sources

These are the limits that apply before WordPress sees the file. All figures are from the primary documentation, read on 11 October 2026.

  • nginx client_max_body_size: default 1m, which is 1,048,576 bytes. Allowed in the http, server and location contexts.
  • PHP upload_max_filesize: default 2M, which is 2,097,152 bytes.
  • PHP post_max_size: default 8M, which is 8,388,608 bytes.
  • Cloudflare maximum upload size: 100 MB on Free and Pro, 200 MB on Business, up to 5 GB on Enterprise. Only applies if the site is proxied.

The byte counts are 1024 times 1024 times the number of megabytes. I computed them in Python rather than by hand.

The order matters. A request passes through Cloudflare first, if you use it, then nginx, then PHP. Whichever layer has the smallest limit rejects it. The nginx default of 1m is smaller than every PHP default, so on a fresh server nginx is usually the one.

Layer 1: nginx and the 413

The nginx documentation says that when the request body is larger than client_max_body_size, nginx returns a 413 (Request Entity Too Large). It also says browsers cannot correctly display this error. That explains why WordPress often shows a vague failure and not the nginx page.

The directive takes a size. Put it in the server block to cover the whole site:

server {
	# ...
	client_max_body_size 64m;
}

Then test the file and reload. I could not run nginx -t here, so this is from the directive documentation, not a test run:

sudo nginx -t && sudo systemctl reload nginx

If you manage the server through a control panel, find its setting for upload size. The panel writes the same directive, and a manual edit may be overwritten on the next change.

On a managed host the setting may live in a per-site nginx include or a control panel field. Look for it by name: “upload size”, “client max body size” or “max request size”. After you set it, test with a file just under the new limit and one just over.

Layer 2: PHP, and why there is no 413

PHP does not send a 413. I tested this locally with the PHP 8.5.10 built-in server and a script that counts $_POST, $_FILES and the content length.

  • Test A: post_max_size=1M, 2 MiB file. The response was HTTP 200 with zero post fields and zero files. The log showed a warning that the POST content length of 2,097,457 bytes exceeds the limit of 1,048,576 bytes.
  • Test B: post_max_size=8M, upload_max_filesize=512K, same file. HTTP 200, one file, upload error code 1, which is UPLOAD_ERR_INI_SIZE.

This matches the manual: if the post data is larger than post_max_size, $_POST and $_FILES are empty. The manual also says post_max_size must be larger than upload_max_filesize.

So a PHP rejection looks like an upload that “worked” and saved nothing. A 413 is not PHP.

Set the two PHP values together, with post_max_size larger than upload_max_filesize, and both at or above the nginx limit:

upload_max_filesize = 64M
post_max_size = 72M

The multipart overhead

A file of exactly the limit does not fit, because the request carries framing around it. In test C, I sent a 1,048,000-byte file with curl -F. The content length that arrived was 1,048,212. That is 212 bytes of multipart framing from curl for that file name.

The nginx limit is 1,048,576 bytes. Subtract 212 and the largest file that fits under 1m with curl’s framing is 1,048,364 bytes. Browsers add their own headers and boundaries, so the exact figure differs. The point is that the limit applies to the whole body, not to the file.

What WordPress shows you

The number in the media uploader comes from wp_max_upload_size() in wp-includes/media.php. It takes the smaller of upload_max_filesize and post_max_size and passes it through the upload_size_limit filter. The uploader script gets it as max_file_size.

It reads PHP settings only. It knows nothing about nginx or Cloudflare. If WordPress says 64 MB and your upload gets a 413, one of the layers outside PHP is lower.

The PHP settings can be set in php.ini, in a PHP-FPM pool file, or in a .user.ini file, depending on the host. Both settings are marked as changeable only per directory or in the system config, so ini_set() from a plugin will not work.

After changing them, restart PHP-FPM. When an update fails for a related reason, see How to fix WordPress automatic updates not working.

Layer 0: Cloudflare

If the site is proxied, Cloudflare sees the request before nginx does. Its documentation lists the maximum upload size as 100 MB on Free and Pro, 200 MB on Business and up to 5 GB on Enterprise, and says it can be adjusted from the zone’s Network page. It also lists a Proxy Write Timeout of 30 seconds on the connection limits page, last updated 23 July 2026.

For most uploads under 100 MB, Cloudflare is not the cause. The way to know which layer answered is your own nginx access log: a request that nginx rejected is logged with status 413, and one that never reached nginx is not in the log at all. Reading WordPress access logs shows how to read that line.

How this was checked

I read the nginx core module page, the PHP ini and file-upload pages, the Cloudflare default cache behavior and connection limits pages, and wp_max_upload_size() in WordPress 7.1.3, all on 11 October 2026. The PHP behaviour is from my local tests with the built-in server.

Browsers may add a different amount of framing than curl, so the 212-byte figure is curl’s only. I did not run nginx, so nginx -t and the config above are untested. I did not test Cloudflare. A Cloudflare 4xx error page I tried to read returned 404, so I do not describe its wording.

Questions people ask

Which setting should I raise first?

Raise nginx client_max_body_size, because its default is the smallest. Then set post_max_size larger than upload_max_filesize.

Why does WordPress say the limit is higher than what works?

It reads only the PHP settings. nginx and Cloudflare limits are invisible to it.

Is a very large limit safe?

A larger limit allows larger request bodies on every URL it covers. Pick a value above your biggest real file, and scope it to the upload location if you can.

Do this today

Run nginx -T | grep client_max_body_size on your server. If nothing prints, you are on the 1m default.

Resources

Tell me where I am wrong

Your email is not published and I do not add it to any list. Corrections with a source are the ones I act on fastest.