NGINX Error Guide: '413 Request Entity Too Large' on uploads
Fix NGINX 413 Request Entity Too Large errors: tune client_max_body_size, align PHP upload limits, fix proxy body size, and place the directive in the right context.
- #nginx
- #troubleshooting
- #errors
- #uploads
Overview
A 413 Request Entity Too Large means the request body the client sent is bigger than client_max_body_size, so NGINX rejects it before passing it to the backend. This is NGINX doing exactly what it was told — the default limit is 1 MB, which is smaller than most file uploads.
The rejection is logged clearly:
2026/06/23 15:04:09 [error] 4015#4015: *30188 client intended to send too large body: 5242880 bytes, client: 203.0.113.55, server: app.example.com, request: "POST /upload HTTP/1.1", host: "app.example.com"
The number (5242880 bytes = 5 MB here) is the size the client tried to send. NGINX closes the request with 413 without ever forwarding the body upstream. The fix is to raise the limit in the correct context — and to keep the backend’s own upload limits in sync.
Symptoms
- File or form uploads fail with “413 Request Entity Too Large”.
- error.log records
client intended to send too large body. - Small uploads work; only files above a threshold (often 1 MB) fail.
- The backend never logs the request — NGINX rejected it before proxying.
curl -sI -X POST -F file=@bigfile.zip https://app.example.com/upload | head -1
HTTP/1.1 413 Request Entity Too Large
sudo grep "too large body" /var/log/nginx/error.log | tail -3
[error] 4015#4015: *30188 client intended to send too large body: 5242880 bytes, request: "POST /upload HTTP/1.1"
Common Root Causes
1. client_max_body_size is unset (default 1 MB)
If you never set the directive, NGINX uses its 1 MB default and rejects anything larger.
grep -RnE 'client_max_body_size' /etc/nginx/nginx.conf /etc/nginx/conf.d/ /etc/nginx/sites-enabled/
(no output — directive is not set anywhere)
[error] 4015#4015: *30188 client intended to send too large body: 2097152 bytes
No match means the 1 MB default applies. A 2 MB upload (2097152 bytes) is refused.
2. The directive is set, but too low for real uploads
It is configured, just below what users actually upload.
grep -RnE 'client_max_body_size' /etc/nginx/
/etc/nginx/conf.d/app.conf:12: client_max_body_size 2m;
[error] 4015#4015: *30188 client intended to send too large body: 5242880 bytes
A 5 MB upload exceeds the 2 MB cap. Raise it to cover your real maximum (for example client_max_body_size 50m;).
3. Directive in the wrong context / overridden by a more specific block
client_max_body_size set in http {} can be overridden by a server {} or location {} that sets a lower value (or none, inheriting differently than you expect).
grep -RnB2 'client_max_body_size' /etc/nginx/conf.d/ /etc/nginx/sites-enabled/
http { client_max_body_size 100m; }
server {
location /upload {
client_max_body_size 1m; # overrides the http-level 100m here
}
}
The upload location re-declares a 1 MB limit that wins over the global 100 MB.
4. Backend (PHP) upload limits lower than NGINX
Even after NGINX accepts the body, PHP can reject it via upload_max_filesize / post_max_size. The symptom differs (the backend errors, not 413), but it is the same class of “limit too low” problem and often discovered together.
grep -E 'upload_max_filesize|post_max_size' /etc/php/8.2/fpm/php.ini
upload_max_filesize = 2M
post_max_size = 8M
If NGINX now allows 50 MB but PHP caps post_max_size at 8 MB, the upload fails at the PHP layer. Raise both to match.
5. proxy_request_buffering off without an upstream limit
With buffering off, NGINX streams the body to the upstream as it arrives; client_max_body_size still applies, and a misread of how it interacts with the backend can cause confusion about where the 413 comes from.
grep -RnE 'proxy_request_buffering|client_max_body_size' /etc/nginx/conf.d/
[error] 4015#4015: *30210 client intended to send too large body: 73400320 bytes, request: "PUT /v1/objects/large"
Even when streaming, NGINX enforces client_max_body_size (here 70 MB exceeds the cap). Set it high enough for streamed objects.
6. A reload was never done after editing the config
The config was raised but the running NGINX still has the old value because it was not reloaded.
grep -RnE 'client_max_body_size' /etc/nginx/conf.d/app.conf
sudo systemctl status nginx | grep -i 'active\|since'
client_max_body_size 50m; # on disk
[error] 4015#4015: *30230 client intended to send too large body: 10485760 bytes
The file says 50 MB but a 10 MB upload still fails — the worker is running the pre-edit config. A reload applies the new value.
Diagnostic Workflow
Step 1: Confirm 413 and the size the client sent
curl -sI -X POST -F file=@bigfile.zip https://app.example.com/upload | head -1
sudo grep "too large body" /var/log/nginx/error.log | tail -3
The log line gives the exact byte count — that is the minimum your limit must exceed.
Step 2: Find every client_max_body_size and its context
grep -RnB2 'client_max_body_size' /etc/nginx/nginx.conf /etc/nginx/conf.d/ /etc/nginx/sites-enabled/
Note whether it is in http, server, or location. The most specific block serving the upload URL wins.
Step 3: Set or raise it in the right place
Put the value where it covers the upload route — typically the server block, or the specific upload location:
server {
client_max_body_size 50m; # covers all locations in this server
...
}
Use a value comfortably above your real maximum upload.
Step 4: Align the backend limits
grep -E 'upload_max_filesize|post_max_size|memory_limit' /etc/php/8.2/fpm/php.ini
Set upload_max_filesize and post_max_size at least as high as NGINX’s limit so the body is not rejected one layer down.
Step 5: Validate and reload (not just save)
sudo nginx -t
sudo systemctl reload nginx
# if you changed PHP limits:
sudo systemctl reload php8.2-fpm
The reload is what actually applies the new limit to live traffic.
Example Root Cause Analysis
Users report that uploading PDFs larger than ~2 MB to /upload fails with 413, while smaller files succeed.
The error log confirms the size and route:
[error] 4015#4015: *30188 client intended to send too large body: 4718592 bytes, request: "POST /upload HTTP/1.1"
Searching the config with context:
grep -RnB2 'client_max_body_size' /etc/nginx/conf.d/ /etc/nginx/sites-enabled/
/etc/nginx/conf.d/app.conf-18- location /upload {
/etc/nginx/conf.d/app.conf:20: client_max_body_size 2m;
There is a client_max_body_size 2m; scoped to the /upload location that overrides a higher value set at the http level. A 4.5 MB PDF exceeds it.
Fix: raise the limit on the upload location to cover real files, align PHP, validate, and reload:
# set client_max_body_size 50m; in location /upload, then:
sudo nginx -t
sudo systemctl reload nginx
sudo systemctl reload php8.2-fpm # after raising post_max_size to 50M
Large uploads now succeed.
Prevention Best Practices
- Set
client_max_body_sizedeliberately in theserver(or uploadlocation) block to your real maximum, plus headroom — never rely on the 1 MB default for anything that takes uploads. - Keep NGINX and backend limits in lockstep:
post_max_sizeandupload_max_filesizein PHP (or the app’s equivalent) should be >= the NGINX value, so a large body never gets rejected one layer deeper. - Audit for stray
location-level overrides; a low limit in a specific block silently defeats a generous global one. - Return a friendly client-side error before the upload starts (check file size in JS) so users get instant feedback instead of a 413 after a long upload.
- Always
nginx -t && systemctl reload nginxafter editing — saving the file alone does nothing until the worker reloads. - For triage when 413s spike after a config change, the free incident assistant can correlate the rejected body sizes with the active limit. More fixes live in the NGINX guides.
Quick Command Reference
# Confirm 413 and the rejected size
curl -sI -X POST -F file=@bigfile.zip https://app.example.com/upload | head -1
sudo grep "too large body" /var/log/nginx/error.log | tail -3
# Find every client_max_body_size and its context
grep -RnB2 'client_max_body_size' /etc/nginx/nginx.conf /etc/nginx/conf.d/ /etc/nginx/sites-enabled/
# Check backend (PHP) upload limits
grep -E 'upload_max_filesize|post_max_size|memory_limit' /etc/php/8.2/fpm/php.ini
# Validate and reload after raising limits
sudo nginx -t && sudo systemctl reload nginx
sudo systemctl reload php8.2-fpm
Conclusion
A 413 is NGINX enforcing client_max_body_size against a body that exceeds it. The usual root causes:
- The directive is unset, so the 1 MB default rejects ordinary uploads.
- It is set but lower than your real maximum upload.
- A more specific
server/locationblock overrides a generous global value. - The backend’s own limits (
post_max_size,upload_max_filesize) are lower than NGINX. - Streamed bodies (
proxy_request_buffering off) still hit the limit. - The config was edited but never reloaded.
Read the rejected byte count in error.log, set client_max_body_size above it in the right context, align the backend limits, then validate and reload. Both layers must agree, or the upload fails at whichever is lower.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.