0. First principle: measure before tuning
Before touching settings:
- Use: PerfMon, dotnet-counters, dotnet-trace, Failed Request Tracing, IIS logs.
- Track at least:
- Requests/sec
- Avg/95th latency
- CPU %
- RAM / GC pauses
- HTTP errors (4xx/5xx)
- Change one thing at a time and compare.
1. OS & Hardware-level optimizations
These are outside IIS but critical:
- Use modern Windows Server (2019+ ideally) – better HTTP.sys, HTTP/2/3 support, TLS performance, etc.
- Enough CPU & RAM; avoid constant >80% CPU.
- Use SSD/NVMe for web content and logs.
- Network:
- Enable RSS/Receive Side Scaling, offloads (checksum, LSO) if appropriate.
- Make sure NIC drivers are updated.
- Power plan: set to High performance on servers.
- Disable unnecessary background services and scheduled tasks that contend for CPU/IO.
2. IIS application pool tuning
2.1 .NET CLR & pipeline
For ASP.NET Core with ANCM:
- Use No Managed Code in app pool (since Core runs out-of-process) – avoids extra .NET overhead in w3wp.
For classic ASP.NET:
- Use Integrated pipeline mode (not Classic) for better performance & features.
2.2 Recycling
Recycling too often kills warm state and hurts latency:
- Disable time-based recycling (e.g., every 29 hours) unless you have a strong reason.
- Prefer recycling on:
- Specific memory limits (if leak suspected)
- Configuration changes (default)
- Use overlapped recycling and preloading to avoid cold start spikes.
2.3 Idle timeout & start mode
- For high-traffic / critical apps:
- Set Idle Time-out higher or 0 (no timeout).
- Enable AlwaysRunning + Application Initialization so app is always warm.
- For many small sites:
- Keep idle timeout to auto-suspend low-traffic apps to save RAM.
2.4 Queue length & throttling
queueLength(Application pool → Advanced settings):- Increase from default (1000) if you see 503.2 (queue full) and backend is still healthy.
- Consider CPU throttling only when you want fairness between sites; it can also become a bottleneck if set too low.
3. Site & connection-level settings
3.1 Max concurrent connections and limits
- Tune connectionTimeout, maxConnections, and request limits (Request Filtering → maxAllowedContentLength, maxRequestLength).
- Too low → users get 400/413; too high → risk of memory exhaustion during attacks.
3.2 HTTP/2 & TLS
- Enable HTTP/2 where possible – especially for many small static resources.
- Use modern cipher suites and TLS session resumption for lower CPU per SSL handshake.
3.3 Keep-alive & pipelining
- Keep-alive enabled to reuse TCP connections.
- Keep-alive timeout: balance between:
- High enough to reuse connections
- Low enough to avoid too many idle connections consuming memory.
4. Caching (the big win)
4.1 Static content caching
- Enable kernel-mode caching and static file caching:
- Client cache: set long
Cache-Controlheaders (public, max-age=31536000) for versioned static assets (CSS/JS/images with hashes). - IIS Output Cache / HTTP.sys: cache frequently requested static responses in memory.
- Client cache: set long
4.2 Dynamic output caching
For pages whose output doesn’t change per-user:
- Use Output Caching:
- Cache by URL + query string + headers as needed.
- Use proper vary-by configuration (e.g.,
VaryByParam,VaryByHeader).
- For ASP.NET Core:
- Use Response Caching middleware or application-level memory/Redis cache.
- Beware: wrong vary rules can show other users’ data → test carefully.
4.3 Partial caching
- For classic ASP.NET: use fragment caching for expensive controls/user controls.
- At app layer: cache heavy data (e.g., dropdown lists, configs) in memory/Redis so IIS doesn’t call DB every request.
5. Compression & content optimization
5.1 Static compression
- Enable static compression for text content (HTML, JS, CSS, JSON, XML).
- Don’t compress:
- Already compressed formats (JPEG, PNG, MP4, ZIP, etc.).
- Make sure compression cache directory is on fast disk.
5.2 Dynamic compression
- Enable dynamic compression carefully:
- Good for APIs returning JSON/HTML.
- Watch CPU – heavy dynamic compression + high concurrency can become bottleneck.
- Use thresholds (e.g., only compress responses > some size).
5.3 Brotli / newer algorithms
- On newer Windows / reverse proxies: enable Brotli for extra savings, especially on text content (if supported by your stack).
6. Modules, handlers & pipeline trimming
Every extra module = extra work per request.
- For each site:
- Go to Modules and remove what you don’t need:
WebDAV,ASP,ISAPI,CGI, etc., if unused.
- Go to Modules and remove what you don’t need:
- For static-only sites:
- Disable ASP.NET, authentication modules, etc.
- For API-only sites:
- You might not need session state / forms auth / etc.
This reduces CPU per request and speeds up pipeline.
7. Logging & diagnostics tuning
Logging is essential but can slow you down if misconfigured.
- W3C access logs:
- Use separate log directory on fast disk.
- Avoid logging fields you don’t need.
- Roll logs daily or by size.
- Failed Request Tracing (FREB):
- Enable only for troubleshooting specific status codes (e.g., 500, 503).
- Turn off once done.
- Don’t write massive logs from app to disk synchronously; use async logging + batching (Serilog/Seq, ELK, etc.).
8. Request filtering & security (for performance & safety)
Tuning security helps performance by rejecting bad traffic early.
- Request Filtering:
- Limit maximum URL length, headers length, body size.
- Block unwanted file extensions, methods, verbs.
- IP restrictions / WAF:
- Use IPRestrictions to block abusive IPs.
- Use external WAF / reverse proxy (F5, Nginx, Azure App Gateway, Cloudflare) to filter bots/attacks before IIS.
- Authentication:
- Avoid enabling multiple auth schemes unnecessarily (e.g., Windows + Anonymous + Basic).
- Use the lightest authentication compatible with your requirements.
9. Pooling & concurrency strategy
9.1 Web gardens (multiple worker processes in one app pool)
- Generally NOT recommended for ASP.NET / ASP.NET Core apps that rely on in-process state (Session/InMemory cache).
- Use scaling out with multiple servers or load balancer instead.
- Only consider web gardens when:
- Stateless app
- You understand affinity/load-balancer behavior.
9.2 Multiple sites on same server
- Make sure heavy sites don’t starve lightweight ones:
- Separate app pools.
- Use CPU limits or move heavy sites to dedicated server.
10. Content & front-end optimizations (indirect IIS wins)
These don’t change IIS itself, but dramatically reduce its load:
- Use CDN for static assets (images, JS, CSS) → fewer hits to IIS.
- Minify & bundle JS/CSS.
- Use image optimization:
- WebP/AVIF where possible.
- Proper sizing; avoid 4K images for thumbnails.
- Reduce number of HTTP requests (sprites, bundling, HTTP/2 multiplexing).
Less work for IIS = better performance and lower cost.
11. ASP.NET / ASP.NET Core specific tuning (on top of IIS)
- GC mode:
- Use Server GC for high-throughput server apps.
- Thread pool tuning only when necessary (usually defaults are fine).
- Avoid blocking calls (
.Result,.Wait()) on async flows → thread starvation. - Optimize EF Core / DB access:
- Use pooling, compiled queries, proper indexes.
- Cache config & lookups; avoid reading from disk/DB each request.
IIS is only part of the chain; app inefficiencies dominate many real issues.
12. Scaling strategies with IIS
When vertical tuning isn’t enough:
- Scale out using:
- Multiple IIS servers behind a load balancer (hardware / software / cloud LB).
- Use sticky sessions if you rely on in-process session state; otherwise move session state to:
- SQL Server / Redis / distributed cache.
- Use blue–green deployments or slots (e.g., Azure App Service) to avoid downtime during releases.
13. A simple priority checklist (what to do first)
If you want a quick actionable order for a new/slow IIS app:
- Measure (PerfMon + app metrics).
- Enable static & dynamic compression (watch CPU).
- Set caching headers for static content.
- Trim unnecessary IIS modules.
- Configure app pool:
- No Managed Code (for ASP.NET Core).
- Disable frequent recycling.
- Increase queue length if necessary.
- Enable Application Initialization + AlwaysRunning for warm startup.
- Move logs to fast disk, trim logged fields.
- Add CDN for static content if traffic is high.
- Optimize DB calls and app-layer caching.
- If still slow: consider scaling out with load balancer.
I’m a DevOps/SRE/DevSecOps/Cloud Expert passionate about sharing knowledge and experiences. I have worked at Cotocus. I share tech blog at DevOps School, travel stories at Holiday Landmark, stock market tips at Stocks Mantra, health and fitness guidance at My Medic Plus, product reviews at TrueReviewNow , and SEO strategies at Wizbrand.
Do you want to learn Quantum Computing?
Please find my social handles as below;
Rajesh Kumar Personal Website
Rajesh Kumar at YOUTUBE
Rajesh Kumar at INSTAGRAM
Rajesh Kumar at X
Rajesh Kumar at FACEBOOK
Rajesh Kumar at LINKEDIN
Rajesh Kumar at WIZBRAND