Are you seeing the dreaded 413 Request Entity Too Large error? The NGINX client_max_body_size directive is almost certainly the cause. This directive controls the maximum size of the client request body. When exceeded, NGINX rejects the request immediately.
In this guide, you will learn how to configure NGINX client_max_body_size properly. You will fix upload errors and handle large file transfers.
Understanding NGINX client_max_body_size
The client_max_body_size directive sets the maximum size of the client request body. NGINX checks the Content-Length header. If the size exceeds the limit, it returns a 413 error.
By default, NGINX sets client_max_body_size to 1 megabyte. This default is often too small for modern applications. File uploads, API payloads, and form submissions frequently need larger limits.
Where You Can Use client_max_body_size
You can set this directive in three contexts:
- http: Applies to all server blocks and locations
- server: Applies to a specific virtual host
- location: Applies to a specific URL pattern
The specific context overrides the general one. Location blocks override server blocks. Server blocks override http. This model allows flexible configuration.
Quick Fix: Setting client_max_body_size
If you see the 413 error and need a quick fix, add this to your server block:
server {
listen 80;
server_name example.com;
client_max_body_size 64m;
# ... rest of your configuration
}
This sets the maximum body size to 64 megabytes. Test and reload your configuration:
nginx -t && nginx -s reload
Under the Hood: How NGINX Checks Body Size
Understanding the size check helps you troubleshoot issues. The behavior differs by transfer method.
Content-Length Based Requests
For standard requests with a Content-Length header, NGINX checks immediately. The check happens after parsing headers but before reading body data. NGINX rejects oversized requests without wasting bandwidth.
When the check fails, NGINX logs:
client intended to send too large body: 10485760 bytes
The number shows how many bytes the client attempted to send.
Chunked Transfer Encoding
For chunked requests, NGINX tracks size incrementally. It sums each chunk as it arrives. If the total exceeds the limit, you see:
client intended to send too large chunked body: 5242880+1048576 bytes
This format shows received bytes plus the current chunk size.
HTTP/2 and HTTP/3 Behavior
Modern protocols handle size checking similarly. NGINX tracks a received counter as data frames arrive. The same limit applies. No special configuration is needed.
Size Format Options
NGINX accepts several size formats:
| Format | Example | Description |
|---|---|---|
| Bytes | 1048576 |
Size in bytes (1MB) |
| Kilobytes | 1024k |
Size in kilobytes |
| Megabytes | 64m |
Size in megabytes |
| Gigabytes | 2g |
Size in gigabytes |
For readability, use the appropriate unit:
client_max_body_size 67108864; # bytes (less readable)
client_max_body_size 65536k; # kilobytes
client_max_body_size 64m; # megabytes (recommended)
Common Mistake: Missing Unit Suffix
A frequent error is forgetting the size suffix:
# WRONG - This is 64 bytes, not 64 megabytes!
client_max_body_size 64;
# CORRECT - 64 megabytes
client_max_body_size 64m;
Without a suffix, NGINX interprets the value as bytes. This causes 413 errors.
Setting client_max_body_size by Context
HTTP Context (Global Setting)
To set a global default, add the directive to the http block:
http {
client_max_body_size 32m;
# This applies to all server blocks
include /etc/nginx/conf.d/*.conf;
}
This works well for consistent limits. Server blocks can still override this value.
Server Context (Per Virtual Host)
For per-site configuration, add the directive to a server block:
server {
listen 80;
server_name uploads.example.com;
root /var/www/uploads;
# This site handles large file uploads
client_max_body_size 500m;
location / {
try_files $uri $uri/ =404;
}
}
Location Context (Per URL Pattern)
Different endpoints may need different limits. Use location blocks:
server {
listen 80;
server_name example.com;
root /var/www/html;
# Default limit for the site
client_max_body_size 10m;
# Small limit for avatar uploads
location /api/avatar {
client_max_body_size 1m;
}
# Large limit for video uploads
location /api/videos {
client_max_body_size 500m;
}
# Admin area needs larger imports
location /admin/import {
client_max_body_size 2g;
}
}
The Inheritance Gotcha with try_files
There is a critical edge case with client_max_body_size inheritance. When requests are internally rewritten via try_files, the directive behaves unexpectedly.
The problem: After an internal rewrite, client_max_body_size cannot be increased in the rewritten location. Only more restrictive values apply. More permissive values are ignored.
Consider this configuration:
server {
listen 80;
server_name example.com;
root /var/www/html;
# Default 1MB limit
client_max_body_size 1m;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
# This 64m limit will NOT apply after try_files rewrite!
client_max_body_size 64m;
fastcgi_pass unix:/run/php-fpm/www.sock;
include fastcgi_params;
}
}
When /upload rewrites to /index.php, the 64m limit is ignored. The 1m server limit applies instead.
Solutions:
- Set the limit at server level (less secure, exposes all paths):
server { client_max_body_size 64m; # ... } - Create an explicit location for upload endpoints (recommended):
location = /upload { client_max_body_size 64m; fastcgi_pass unix:/run/php-fpm/www.sock; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root/index.php; }
For a deep dive into this behavior, see our article on client_max_body_size inheritance.
Disabling the Size Limit Entirely
Setting client_max_body_size to 0 disables size checking:
location /internal/sync {
client_max_body_size 0;
}
When zero, NGINX skips the size comparison. The request body can be any size. NGINX source code confirms this: it checks if the value is non-zero before comparing.
Warning: Use with extreme caution. Without limits, malicious clients could send huge requests. This could exhaust server resources. Only use zero for trusted internal endpoints.
Complete Configuration Examples
WordPress Configuration
WordPress sites need increased limits for media uploads:
server {
listen 80;
server_name wordpress.example.com;
root /var/www/wordpress;
index index.php index.html;
# WordPress general upload limit - set at server level
# to avoid try_files inheritance issues
client_max_body_size 64m;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
# WooCommerce and large imports in admin
location ~ ^/wp-admin/.*\.php$ {
client_max_body_size 256m;
fastcgi_pass unix:/run/php-fpm/www.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# Timeouts for large uploads
fastcgi_read_timeout 300s;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php-fpm/www.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
API Server Configuration
Modern APIs need to handle large payloads:
server {
listen 80;
server_name api.example.com;
# Default API limit
client_max_body_size 16m;
# Optimize for API requests
client_body_buffer_size 128k;
client_body_timeout 60s;
location /v1/upload {
client_max_body_size 100m;
proxy_pass http://backend;
proxy_request_buffering off;
}
location /v1/ {
proxy_pass http://backend;
}
}
Reverse Proxy Configuration
For reverse proxy setups, adjust limits accordingly:
upstream backend {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name app.example.com;
client_max_body_size 50m;
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# For large uploads, disable request buffering
proxy_request_buffering off;
}
}
Related Directives You Should Know
Several directives work with client_max_body_size. These control body handling.
client_body_buffer_size
Sets the buffer size for reading request bodies:
client_body_buffer_size 128k;
Default is typically 8KB (two memory pages). When exceeded, NGINX writes to a temp file. Larger buffers improve upload performance.
client_body_timeout
Sets a timeout for reading the request body:
client_body_timeout 60s;
The timeout applies between read operations, not the entire transfer. Increase for large uploads over slow connections. For timeout issues, see our guide on fixing 504 Gateway Timeout errors.
client_body_temp_path
Specifies the temporary file directory:
http {
client_body_temp_path /var/lib/nginx/tmp/client_body 1 2;
}
NGINX workers must have write permissions to this directory.
PHP Configuration: The Other Half
With PHP-FPM, client_max_body_size is only half the solution. PHP has its own limits. For PHP-FPM performance, review our guide on NGINX FastCGI Keepalive.
PHP Settings That Affect Uploads
Check your current PHP limits:
php -i | grep -E "(upload_max_filesize|post_max_size|memory_limit)"
Default values are restrictive:
upload_max_filesize = 2M
post_max_size = 8M
memory_limit = 128M
Aligning NGINX and PHP Limits
Your limits must be aligned:
memory_limit > post_max_size >= upload_max_filesize
NGINX client_max_body_size >= post_max_size
For 64MB uploads, configure both:
NGINX:
client_max_body_size 64m;
PHP (php.ini or pool config):
upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M
For pool-specific settings:
; /etc/php-fpm.d/www.conf
php_admin_value[upload_max_filesize] = 64M
php_admin_value[post_max_size] = 64M
php_admin_value[memory_limit] = 256M
Troubleshooting 413 Errors
Check Your Current Configuration
Find where client_max_body_size is set:
grep -r "client_max_body_size" /etc/nginx/
Verify the Applied Limit
Location blocks override server blocks. Server blocks override http. But remember: internal rewrites can prevent location overrides from applying.
Check NGINX Error Log
The error log shows rejected requests:
tail -f /var/log/nginx/error.log
A 413 error shows:
client intended to send too large body: 10485760 bytes
Testing Your Configuration
Create a test file and verify:
# Create a 50MB test file
dd if=/dev/zero of=/tmp/testfile bs=1M count=50
# Test upload
curl -X POST -F "file=@/tmp/testfile" http://localhost/upload
Performance Considerations
Memory Usage
The client_body_buffer_size affects memory directly:
Memory = concurrent_uploads Γ client_body_buffer_size
With 100 uploads and 1MB buffers, you need 100MB of memory.
Disk I/O
When bodies exceed the buffer, NGINX writes temp files. Use fast storage for client_body_temp_path.
Request Buffering
For proxies, proxy_request_buffering affects handling:
# Buffer entire request before forwarding (default)
proxy_request_buffering on;
# Stream to backend as data arrives
proxy_request_buffering off;
Disabling buffering reduces memory. Your backend must handle slow clients.
Security Considerations
Protect Against Resource Exhaustion
Large limits enable denial-of-service attacks. Apply generous limits only where needed:
# Restrictive default
client_max_body_size 1m;
# Generous only for specific paths
location /upload {
client_max_body_size 100m;
# Add rate limiting
limit_req zone=uploads burst=5 nodelay;
}
For rate limiting, see our guide on NGINX rate limiting.
Use Authentication
Combine large limits with authentication:
location /admin/import {
client_max_body_size 2g;
auth_basic "Admin Area";
auth_basic_user_file /etc/nginx/.htpasswd;
}
Monitor Upload Activity
Log large uploads:
log_format uploads '$remote_addr - $request_length bytes - $request_uri';
location /upload {
client_max_body_size 100m;
access_log /var/log/nginx/uploads.log uploads;
}
Common Mistakes to Avoid
Mistake 1: Wrong Context
Placing the directive outside valid contexts fails:
# Wrong - not in http, server, or location
client_max_body_size 64m;
http {
# ...
}
Mistake 2: Forgetting PHP Limits
Only increasing NGINX limits causes different errors when PHP limits remain low.
Mistake 3: Not Reloading
After changes, reload NGINX:
nginx -t && nginx -s reload
Mistake 4: Typos in Size Format
# Wrong - missing suffix (64 bytes!)
client_max_body_size 64;
# Correct
client_max_body_size 64m;
Mistake 5: Ignoring try_files Behavior
Setting limits in PHP locations wonβt work if requests arrive via try_files rewrites. Set the limit at server level or use explicit location matches.
Recommended Settings by Use Case
Battle-tested values for common scenarios:
| Use Case | Value | Notes |
|---|---|---|
| Basic website | 10m |
Sufficient for contact forms |
| WordPress blog | 64m |
Handles most media uploads |
| E-commerce | 128m |
Product images and imports |
| Video platform | 500m β 2g |
Depends on video quality |
| API endpoint | 16m |
JSON payloads rarely exceed this |
| Internal sync | 0 |
Only for trusted networks |
Summary
The NGINX client_max_body_size directive controls upload sizes. Key points:
- Default value is 1 megabyte
- Location blocks can set path-specific limits
- Setting to
0disables checking entirely - Watch out for try_files inheritance issues
- Align with PHP limits when using PHP-FPM
- Consider security implications
For WordPress sites, 64m at the server level provides a good balance. For large files, adjust based on your needs.
Always test with nginx -t before reloading.

