# IIS request filtering, upload limits and timeouts that cause 413/504

> Tune IIS request limits, upload size, header/URL limits and timeout settings deliberately, and tell 413, 404.13 and 504 apart.

**Tested on**

- Build: 26100.33650
- Edition: Standard / Datacenter
- Architecture: x64
- Evidence: E1
- Verified: 2026-10-29

## The short answer

Three different limits produce three different symptoms:

| Symptom | Layer | Setting |
|---|---|---|
| **413.1** / connection reset on upload | Request filtering | `maxAllowedContentLength` |
| **404.13** | Request filtering | content length limit on handler |
| **404.15** | Request filtering | query string limit |
| **400** / bad request | HTTP.sys | URL/header size, malformed host |
| **504** | proxy/app timeout | ARR/ANCM/app timeout |
| Slow upload / disconnect | HTTP.sys | `minBytesPerSecond`, `connectionTimeout` |

Do not raise every limit to “unlimited”. Each one is a DoS control.

## Request filtering

```xml
<system.webServer>
  <security>
    <requestFiltering>
      <requestLimits maxAllowedContentLength="104857600"
                     maxUrl="4096"
                     maxQueryString="2048" />
      <fileExtensions allowUnlisted="true" />
    </requestFiltering>
  </security>
</system.webServer>
```

`maxAllowedContentLength` is in **bytes** (100MB above). The old ASP.NET `maxRequestLength` is in **KB** and only applies to ASP.NET requests; do not confuse them.

Also check handler-level limits (e.g. ASP.NET `maxRequestLength`, `maxJsonLength`) and any reverse proxy body limit.

## Timeouts

- **HTTP.sys / connection**: `connectionTimeout`, `headerWaitTimeout`, `minBytesPerSecond`.
- **IIS request**: `serverRuntime requestTimeout` (default 00:02:00) — long uploads/exports may need more.
- **App pool**: idle timeout is not a request timeout; it stops an idle worker.
- **ARR/ANCM/app**: upstream timeout; a 504 means the front end waited and gave up.

Set timeouts based on the slowest legitimate request, not on “make 504 go away”. A long-running report should be async, not a 30-minute HTTP request.

## Verify

```powershell
Get-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' `
  -Filter 'system.webServer/security/requestFiltering/requestLimits' -Name '.'

curl.exe -I -H "Content-Length: 200000000" http://lab.local/upload
```

Test with a file just below and just above the limit; check the IIS log `sc-status`/`sc-substatus` and the failed request trace.

> **Caution: Limits are not authorization**
>
> A larger upload limit does not make an upload endpoint safe. Validate content type, extension, size, and store uploads outside the executable web root.

## Common mistakes

- Raising `maxAllowedContentLength` but leaving the app’s own limit at 30MB.
- Setting `requestTimeout` to 24 hours for one slow report.
- Disabling request filtering to “fix” a 404.13.
- Forgetting the reverse proxy’s `client_max_body_size`/ARR limit.
- Logging the entire request body for debugging.

## Lab boundary

E1. The lab did not generate a 413/504 or change these limits; the commands and status table are the verification plan for Server 2025.

## Sources

- [Microsoft Learn — Request filtering](https://learn.microsoft.com/en-us/iis/configuration/system.webserver/security/requestfiltering/)
- [Microsoft Learn — Request limits](https://learn.microsoft.com/en-us/iis/configuration/system.webserver/security/requestfiltering/requestlimits/)
- [Microsoft Learn — serverRuntime](https://learn.microsoft.com/en-us/iis/configuration/system.webserver/serverruntime/)

---

Source: https://windows.homes/en/server/web/iis-request-limits/
