IIS Application Pool Tuning for Production on Windows Server
Tune IIS application pools for production on a Windows VPS: idle timeout, AlwaysRunning, No Managed Code, recycling, identity, and memory limits.

On this page
- In short
- Quick verdict
- Why IIS Application Pools matter
- What we tested on Raff
- What you'll need
- Step 1 - Review existing application pools
- Step 2 - Create a dedicated app pool
- Step 3 - Tune idle timeout
- Step 4 - Set start mode to AlwaysRunning
- Step 5 - Set No Managed Code for ASP.NET Core
- Step 6 - Configure recycling
- Step 7 - Set a private memory recycle limit
- Step 8 - Choose the right application pool identity
- Step 9 - Verify final app pool settings
- Recommended production baseline
- Application Initialization
- CPU and queue settings
- Rapid-Fail Protection
- Common mistakes
- What Raff recommends
- Tested on
- What's next
- Sources
Don't have a Windows Server yet?
Deploy Windows Server 2019/2022/2025 in ~2 minutes. 6-month evaluation licence included.
In short
IIS Application Pools control how your web app runs on Windows Server: process identity, idle timeout, start mode, memory-based recycling, regular recycling, and runtime behavior. The defaults are acceptable for simple development sites, but production apps need safer settings. For most production IIS workloads, use one app pool per site, keep the app warm with AlwaysRunning, disable or extend idle timeout, set a private memory recycle limit, and verify the final configuration with PowerShell.
Quick verdict
| Situation | Recommended action |
|---|---|
| Production web app | Use a dedicated app pool |
| ASP.NET Core app | Set managed runtime to No Managed Code |
| App has cold starts after idle periods | Set idle timeout to 0 and start mode to AlwaysRunning |
| App memory usage grows over time | Set a private memory recycle limit |
| Multiple apps share one pool | Split into separate pools for isolation |
| App needs network resources under a specific account | Use a dedicated service account |
| Low-traffic dev/test app | Defaults may be acceptable |
The goal is not to tune every IIS setting. The goal is to prevent cold starts, isolate apps, limit memory damage from leaks, and make app pool behavior predictable.
Why IIS Application Pools matter
An IIS application pool wraps one or more web applications inside a worker process named w3wp.exe.
Application pool settings control:
- Which identity the app runs as
- Whether the app pool starts on demand or stays warm
- When idle worker processes are stopped
- When the worker process recycles
- Whether the pool loads the .NET Framework CLR
- How much private memory the process can use before recycling
- How failures are handled
For production hosting, application pools are one of the most important IIS isolation boundaries.
A practical rule:
One production site should have its own application pool.
This way, a crash, memory leak, or recycle in one app does not automatically affect unrelated apps.
What we tested on Raff
We tested this walkthrough on a Raff Windows VPS running Windows Server 2025 Datacenter Evaluation with IIS installed.

Test environment:
| Item | Value |
|---|---|
| Provider | Raff Technologies |
| OS | Windows Server 2025 Datacenter Evaluation |
| IIS | IIS 10 |
| Test app pool | RaffTestAppPool |
| Test date | 2026-05-26 |
| Tester | Aybars Altinyay |
On this VM, we verified:
- IIS feature state
- IIS Manager Application Pools view
- Creation of a test application pool
- Application pool recycling settings
- Final app pool configuration with PowerShell
We used a test app pool named RaffTestAppPool. We did not tune a live production website in this lab.
What you'll need
- A Raff Windows VPS running Windows Server
- IIS installed
- IIS Management Console installed
- Local administrator access
- PowerShell running as Administrator
- A test app pool or a maintenance window for production changes
If IIS is not installed yet, install it with:
powershellInstall-WindowsFeature Web-Server, Web-Mgmt-Console, Web-Scripting-Tools -IncludeManagementTools
Then open IIS Manager with:
textWin + R -> inetmgr
Step 1 - Review existing application pools
Before changing anything, review the current application pools.
Open IIS Manager:
textStart -> Internet Information Services (IIS) Manager -> Application Pools

You can also list app pools with PowerShell:
powershellImport-Module WebAdministration
Get-ChildItem IIS:\AppPools
For each production app, check:
| Setting | Why it matters |
|---|---|
| Name | Should clearly match the site/app |
| State | Started or stopped |
| .NET CLR version | ASP.NET Core usually needs No Managed Code |
| Identity | Controls file, network, and database access |
| Idle timeout | Affects cold starts |
| Recycling | Affects process restarts |
| Private memory limit | Limits damage from memory leaks |
Avoid changing multiple pools at once. Tune one app pool, test the app, then continue.
Step 2 - Create a dedicated app pool
For the lab, we created a dedicated test app pool:
powershellImport-Module WebAdministration
New-WebAppPool -Name "RaffTestAppPool"
Get-Item IIS:\AppPools\RaffTestAppPool

For production, use clear names:
textexample.com
api.example.com
customer-portal
quickbooks-webconnector
internal-erp
Do not put every site into DefaultAppPool.
A dedicated app pool gives you:
- Better isolation
- Separate recycle behavior
- Separate identity
- Easier troubleshooting
- Cleaner performance monitoring
Step 3 - Tune idle timeout
The default IIS idle timeout is commonly 20 minutes. After the app pool receives no traffic for that period, IIS can stop the worker process.
For low-traffic production apps, this causes cold starts. The first user after an idle period may wait several seconds while the app starts again.
For production user-facing apps, disable idle timeout:
powershellSet-ItemProperty IIS:\AppPools\RaffTestAppPool -Name "processModel.idleTimeout" -Value "00:00:00"
Alternative: set a long timeout, such as 8 hours:
powershellSet-ItemProperty IIS:\AppPools\RaffTestAppPool -Name "processModel.idleTimeout" -Value "08:00:00"
Use this guidance:
| App type | Suggested idle timeout |
|---|---|
| Production customer-facing app | 00:00:00 |
| Internal app used all day | 00:00:00 or long timeout |
| Low-traffic dev/test app | Default may be fine |
| Memory-constrained server | Use a longer timeout instead of disabling |
Disabling idle timeout keeps the worker process warm, but it also keeps memory allocated. Make sure the VPS has enough RAM.
Step 4 - Set start mode to AlwaysRunning
Idle timeout controls when the process stops after inactivity. Start mode controls whether IIS starts the application pool proactively or waits for the first request.
For production, set:
powershellSet-ItemProperty IIS:\AppPools\RaffTestAppPool -Name "startMode" -Value "AlwaysRunning"
Recommended combination:
| Setting | Production value |
|---|---|
| Idle timeout | 00:00:00 |
| Start mode | AlwaysRunning |
This reduces cold starts and helps keep the app ready for traffic.
For full warm-up behavior, pair this with Application Initialization when appropriate.
Step 5 - Set No Managed Code for ASP.NET Core
For ASP.NET Core apps hosted behind IIS, the application pool should normally use:
textNo Managed Code
Set it with PowerShell:
powershellSet-ItemProperty IIS:\AppPools\RaffTestAppPool -Name "managedRuntimeVersion" -Value ""
Why this matters:
- ASP.NET Core runs on the .NET runtime through the ASP.NET Core Module
- IIS does not need to load the classic .NET Framework CLR for the app pool
- Incorrect CLR settings can cause confusion during troubleshooting
Use this guidance:
| App type | Managed runtime setting |
|---|---|
| ASP.NET Core | No Managed Code |
| Classic ASP.NET Framework app | .NET CLR version v4.0 |
| Static site | No Managed Code |
| Reverse proxy to Kestrel | No Managed Code |
If your app is a classic ASP.NET Framework app, do not blindly set No Managed Code. Match the runtime to the application.
Step 6 - Configure recycling
Application pool recycling restarts the worker process. This can recover memory from leaks and apply changes, but recycling too often can hurt performance.
IIS has a default regular time interval recycle. Many IIS environments use a default of 1740 minutes, or 29 hours, which avoids recycling at the exact same time every day.

Common recycling options:
| Recycle trigger | Use when |
|---|---|
| Regular time interval | General safety net |
| Specific time | You want predictable overnight recycle |
| Private memory limit | You want to recycle leaky apps |
| Request count | Rarely needed for normal SMB apps |
| Config change | IIS handles this automatically |
For stable production apps, the default recycle interval is often acceptable.
For apps with suspected memory leaks, consider a controlled recycle window:
textRecycle daily at 03:00
Avoid aggressive recycling such as every 30 minutes unless you are temporarily mitigating a serious issue. Frequent recycling destroys warm caches and can make users feel random slowdowns.
Step 7 - Set a private memory recycle limit
The private memory limit is a safety cap. When the worker process exceeds the configured private memory limit, IIS recycles the application pool.
IIS expects the value in KB.
Example: set a 1 GB private memory recycle limit:
powershellSet-ItemProperty IIS:\AppPools\RaffTestAppPool -Name "recycling.periodicRestart.privateMemory" -Value 1048576
Reference values:
| Memory cap | Value in KB |
|---|---|
| 512 MB | 524288 |
| 1 GB | 1048576 |
| 1.5 GB | 1572864 |
| 2 GB | 2097152 |
| 4 GB | 4194304 |
Use this carefully. If the cap is too low, the app may recycle during normal traffic. If the cap is too high, a memory leak can hurt the entire VPS.
For an 8 GB VPS hosting a few small apps, a 1-2 GB cap per app pool is a reasonable starting point. Adjust based on real memory usage.
Step 8 - Choose the right application pool identity
The default identity is usually:
textApplicationPoolIdentity
This is a good default for most apps. It gives each app pool a virtual account and helps isolate file access.
Use ApplicationPoolIdentity when:
- The app only needs local file access
- The app connects to databases with SQL authentication or app-managed credentials
- You want simple isolation
- You do not need domain/network access as a specific user
Use a dedicated service account when:
- The app needs to access a network file share
- SQL Server uses Windows Authentication
- The app must authenticate to another internal service
- You need auditable identity across systems
Example service account configuration:
powershell$cred = Get-Credential
Set-ItemProperty IIS:\AppPools\RaffTestAppPool -Name "processModel.identityType" -Value 3
Set-ItemProperty IIS:\AppPools\RaffTestAppPool -Name "processModel.userName" -Value $cred.UserName
Set-ItemProperty IIS:\AppPools\RaffTestAppPool -Name "processModel.password" -Value $cred.GetNetworkCredential().Password
Do not use a personal admin account as an application pool identity.
Step 9 - Verify final app pool settings
After applying changes, verify the final configuration.
Run:
powershellGet-ItemProperty IIS:\AppPools\RaffTestAppPool |
Select-Object name, state, managedRuntimeVersion, startMode,
@{Name="IdleTimeoutMinutes";Expression={$_.processModel.idleTimeout.TotalMinutes}},
@{Name="PrivateMemoryKB";Expression={$_.recycling.periodicRestart.privateMemory}},
@{Name="RecycleIntervalMinutes";Expression={$_.recycling.periodicRestart.time.TotalMinutes}}

In our lab, we verified:
| Setting | Test value |
|---|---|
| App pool name | RaffTestAppPool |
| Managed runtime | No Managed Code |
| Start mode | AlwaysRunning |
| Idle timeout | 0 minutes |
| Private memory limit | 1048576 KB |
| Recycle interval | IIS default / configured value |
This gives you a clear proof point before applying similar settings to production pools.
Recommended production baseline
For a typical ASP.NET Core production app on IIS:
| Setting | Recommended starting value |
|---|---|
| App pool per site | Yes |
| Identity | ApplicationPoolIdentity or service account if needed |
| Managed runtime | No Managed Code |
| Start mode | AlwaysRunning |
| Idle timeout | 0 |
| Regular recycle | Default or scheduled off-hours |
| Private memory limit | Based on VPS size and app behavior |
| Application Initialization | Enable for apps with cold-start issues |
For classic ASP.NET Framework apps, keep the appropriate .NET CLR version instead of using No Managed Code.
Application Initialization
Application Initialization can warm up the application after a recycle or restart.
This is useful when:
- The first request is slow
- The app builds caches at startup
- The app opens database connections at startup
- You have a health endpoint such as
/health
Example web.config pattern:
xml<system.webServer>
<applicationInitialization doAppInitAfterRestart="true">
<add initializationPage="/health" />
</applicationInitialization>
</system.webServer>
You may also need to enable preload on the site or application.
Use this only if the app has a safe warm-up endpoint.
CPU and queue settings
Most SMB apps do not need CPU limits at first. However, they are useful when multiple apps share one VPS and one app can consume too much CPU.
Settings to review:
| Setting | Purpose |
|---|---|
| CPU limit | Caps CPU behavior for a pool |
| Limit action | Controls what IIS does when limit is reached |
| Queue length | Controls request backlog |
| Rapid-Fail Protection | Stops repeated crash loops |
Do not tune CPU limits blindly. Start with monitoring. If one app repeatedly starves the server, then consider limits or move that app to another VPS.
Rapid-Fail Protection
Rapid-Fail Protection stops an app pool if the worker process crashes too many times in a short period.
This protects the server from endless crash loops.
Use it when:
- The app has startup failures
- Bad deployments cause repeated crashes
- You want IIS to stop retrying until an admin investigates
Do not simply disable Rapid-Fail Protection to hide a broken app. Fix the crash reason.
Common mistakes
Leaving default idle timeout on production apps
A 20-minute idle timeout can create cold starts for the next user. For production apps, use 00:00:00 when the VPS has enough memory.
Putting many sites into one app pool
One app crash or recycle can affect every site in the pool. Use one app pool per production site.
Forgetting No Managed Code for ASP.NET Core
ASP.NET Core apps usually do not need the classic .NET CLR loaded in the IIS app pool.
Setting private memory limit too low
If the cap is too low, normal traffic can trigger unnecessary recycles.
Setting no memory limit for leaky apps
If an app has a memory leak, unlimited private memory can hurt the entire VPS.
Using the wrong identity
ApplicationPoolIdentity is a good default, but apps that need network access or Windows Authentication to SQL Server may need a service account.
Recycling too often
Frequent recycling clears warm caches and can create random slow first requests.
What Raff recommends
For production IIS workloads on a Windows VPS, Raff recommends:
- Use one app pool per production site.
- Use clear app pool names.
- Use ApplicationPoolIdentity unless the app needs a service account.
- Use No Managed Code for ASP.NET Core apps.
- Set Start Mode to AlwaysRunning for production apps.
- Disable idle timeout for production apps that should stay warm.
- Set private memory recycle limits based on VPS size.
- Schedule recycling during low-traffic hours if needed.
- Verify settings with PowerShell.
- Monitor memory and response time after changes.
The right settings depend on the app. Start with safe defaults, then tune based on actual behavior.
Tested on
Tested on Raff Windows VPS, Windows Server 2025 Datacenter Evaluation, IIS 10, 2026-05-26. We created a test application pool named RaffTestAppPool, applied production-style settings for idle timeout, start mode, managed runtime, and private memory recycling, then verified the final configuration with PowerShell. Tester: Aybars Altinyay.
What's next
- Deploy ASP.NET Core to IIS on Windows Server - deploy a .NET app behind IIS on a Windows VPS
- Configure Windows Firewall on a Windows VPS - control inbound access for IIS, RDP, and SQL Server
- Windows Update Strategy on Production Servers - patch Windows Server safely with snapshots and maintenance windows
- Windows Server Hardening Checklist - secure a Windows Server VPS before production
- Raff Windows VPS - deploy a Windows Server VPS for IIS, SQL Server, ASP.NET, and business apps
Sources
- Microsoft Learn - IIS Application Pool Identities
- Microsoft Learn - Configure IIS Application Pool Recycling
- Microsoft Learn - Application Initialization
- Microsoft Learn - Application Pool Defaults
- Date last verified: 2026-05-26
Related articles
RDP Performance Tuning for Smooth Remote Desktop
Tune Remote Desktop on a Windows VPS by checking RDP connectivity, AVC 444 policy, visual effects, client settings, and server CPU/RAM usage.
MSSQL Memory Tuning on a Windows VPS: Set Max Server Memory Safely
Learn how to set SQL Server max server memory on a Windows VPS, reserve RAM for Windows, and verify the setting with sqlcmd.