How to Resolve "Nginx 413 Request Entity Too Large" Upload Error
Quick answer
A file upload that should work fails immediately with a 413 status instead of reaching your application code at all. Nginx rejects request bodies larger than...
A file upload that should work fails immediately with a 413 status instead of reaching your application code at all. Nginx rejects request bodies larger than its configured limit before your backend ever sees them, which means the fix belongs entirely in Nginx configuration, not your application.
The Problem
An upload request fails instantly, often before any meaningful upload progress is even shown client-side:
$ curl -X POST https://yourapp.com/upload -F "file=@large-video.mp4"
<html>
<head><title>413 Request Entity Too Large</title></head>
<body>
<center><h1>413 Request Entity Too Large</h1></center>
<center>nginx</center>
</body>
</html>
The Nginx error log confirms it's a body size rejection, not an application error:
2026/08/07 15:10:02 [error] 8821#8821: *201 client intended to send too large body:
15728640 bytes, client: 203.0.113.5, server: yourapp.com, request: "POST /upload HTTP/1.1"
Why It Happens
Nginx defaults to a very conservative client_max_body_size of 1MB, which is far too small for file uploads, image galleries, or API payloads carrying attachments. Since this check happens at the Nginx level before your request is proxied anywhere, it rejects oversized requests immediately, which is actually useful protection against abuse β but it needs to be explicitly raised for any application that legitimately handles larger uploads. Common contributing factors:
- The directive was never changed from its restrictive default anywhere in the config.
- It was set in the wrong config block β a setting inside
http {}doesn't automatically apply if a more specificserver {}orlocation {}block overrides it with a stricter value later. - Nginx was updated or reconfigured (a new site added, a config regenerated by a tool like Certbot or a control panel) and the previous limit override got lost in the process.
- There's a reverse proxy or load balancer in front of Nginx with its own separate, smaller body size limit that's rejecting the request before it even reaches Nginx.
The Fix
Set client_max_body_size to a value appropriate for your largest expected upload. It can go in the http, server, or location block depending on how broadly you want it to apply:
http {
client_max_body_size 50M;
}
For a limit specific to just the upload endpoint, scope it more narrowly instead of raising it globally:
server {
location /upload {
client_max_body_size 100M;
}
}
Reload Nginx for the change to take effect (a full restart isn't necessary):
sudo nginx -t
sudo systemctl reload nginx
nginx -t validates the config syntax before reloading, which catches typos before they take down your running server. If your application also processes uploads through PHP, remember Nginx's limit isn't the only one in play β PHP has its own separate settings that need to match:
; php.ini
upload_max_filesize = 50M
post_max_size = 55M
post_max_size should be set slightly higher than upload_max_filesize to account for other form fields sent alongside the file itself.
Still Not Working?
If you've raised the limit and reloaded but still get 413 errors, check for a second server or location block that might be matching the same request with a stricter, unintended override β Nginx uses the most specific matching block, so a broad client_max_body_size 50M; in http {} can still be overridden by a narrower location block elsewhere that still has the old default:
grep -rn "client_max_body_size" /etc/nginx/
This searches every config file for every instance of the directive, making it easy to spot a conflicting or forgotten override. If you're behind a load balancer, CDN, or reverse proxy in front of Nginx (Cloudflare, AWS ALB, another Nginx instance), check its documentation for an equivalent body size limit β these are configured entirely separately from your own Nginx instance and will reject the request before it ever reaches your server if left at their own defaults.