Acumatica is an ASP.NET application, and every instance you deploy runs inside an IIS application pool. That pool is a Windows process (w3wp.exe) that holds the loaded assemblies, the compiled graphs, the in-memory caches, and the ambient state the framework builds up on first use. Most of the "Acumatica is slow in the morning" and "the site randomly logs everyone out" complaints I get called about are not database problems — they are the application pool recycling or being killed on idle, then paying the full cold-start cost on the next request.
Why the application pool matters for Acumatica
When a fresh w3wp.exe handles its first request, Acumatica has to JIT-compile business logic, load the customization projects published to that site, warm its metadata caches, and re-establish database connections. On a real instance with a few published customizations, that cold start is measured in tens of seconds. As long as the pool stays warm, subsequent requests are fast. So tuning the pool is mostly about one thing: keeping it alive and avoiding recycles that throw away all that warm state during business hours.
You configure this per site in IIS Manager under Application Pools → (your pool) → Advanced Settings, or with appcmd / PowerShell. Four settings do most of the work.
Idle time-out: turn it off
By default IIS shuts an application pool down after 20 minutes with no requests, to free memory. For a shared web host that is sensible. For a line-of-business ERP that a handful of users hit all day, it is exactly wrong: the pool dies during a quiet lunch hour and the first person back pays the cold start. Set Idle Time-out (minutes) to 0 so the pool never idles out.
Import-Module WebAdministration
# Never shut down on idle
Set-ItemProperty "IIS:\AppPools\AcumaticaPool" `
-Name processModel.idleTimeout -Value ([TimeSpan]::Zero)
# Belt-and-braces: keep the worker warm even with zero traffic
Set-ItemProperty "IIS:\AppPools\AcumaticaPool" `
-Name processModel.idleTimeoutAction -Value Suspend
On IIS 8.5+ you can also set startMode to AlwaysRunning and enable Application Initialization so the pool warms itself after a recycle instead of waiting for a user to trigger the cold start. That pairs well with the recycling settings below.
Recycling: schedule it, don't let it surprise you
IIS recycles a pool to reclaim leaked memory and reset a process that has been running for a long time. The defaults recycle on a rolling 29-hour interval (periodicRestart.time = 1740 minutes), which means the recycle time drifts across the clock and will eventually land in the middle of your busiest hour. The fix is to remove the interval-based recycle and use a specific time outside business hours instead.
# Disable the rolling time interval
Clear-ItemProperty "IIS:\AppPools\AcumaticaPool" `
-Name recycling.periodicRestart.time
Set-ItemProperty "IIS:\AppPools\AcumaticaPool" `
-Name recycling.periodicRestart.time -Value "00:00:00"
# Recycle once, at 02:30, when nobody is on
Clear-ItemProperty "IIS:\AppPools\AcumaticaPool" `
-Name recycling.periodicRestart.schedule
New-ItemProperty "IIS:\AppPools\AcumaticaPool" `
-Name recycling.periodicRestart.schedule -Value @{value="02:30:00"}
By default IIS uses an overlapped recycle: it spins up a new worker before killing the old one, which is good for availability. But long-running Acumatica processing (a big AP release, an import scenario, an integration push) that is mid-flight in the old worker can still be cut off when the old process is finally terminated. Schedule the recycle for a genuinely quiet window, and avoid manual recycles while a large operation is running.
Memory limits, not just time
A time-based recycle every night handles slow leaks. It does not protect you from a single request that balloons memory — an export of a huge dataset, a report with no filter, a runaway customization. For that, set a private memory limit so a pool that grows past a sane ceiling recycles on its own rather than dragging the whole server into paging. Pick a number that fits the RAM you have and the number of sites on the box; on a dedicated instance with 16 GB, a limit somewhere in the low gigabytes per pool is a reasonable starting point that you then tune against observed steady-state usage.
# privateMemory is in KB. 4 GB = 4194304 KB. Tune to your box.
Set-ItemProperty "IIS:\AppPools\AcumaticaPool" `
-Name recycling.periodicRestart.privateMemory -Value 4194304
Leave the virtual-memory limit alone on 64-bit systems — privateMemory is the one that reflects real usage. And watch the event log: repeated memory-triggered recycles during the day are a signal that something in a customization or a report is leaking, not that the limit is too low.
Queue length and worker processes
The queue length (HTTP.sys request queue, default 1000) is how many requests can wait for the pool before IIS returns a 503. For a normal Acumatica user count 1000 is plenty; you only raise it if you have genuine bursts that briefly exceed the pool's throughput and you would rather queue than reject. Raising it does not add capacity — it just changes a fast failure into a slow one, so treat a full queue as a sign to look at the database or the code path, not as a reason to keep bumping the number.
Leave Maximum Worker Processes at 1. A web garden (multiple worker processes per pool) breaks Acumatica's in-process caching and its default session model, because state built up in one worker is invisible to the others. If you need to scale beyond one process, scale out to multiple instances behind a load balancer with sticky sessions instead of turning the single pool into a garden.
The settings that matter, in one place
| Setting | Default | Recommended for Acumatica |
|---|---|---|
| Idle Time-out | 20 min | 0 (never idle out) |
| Regular Time Interval recycle | 1740 min (rolling) | Disabled; use a specific off-hours time |
| Specific Times recycle | — | One nightly time, e.g. 02:30 |
| Private Memory Limit | 0 (none) | A ceiling that fits your RAM, tuned to steady state |
| Queue Length | 1000 | Leave unless you have measured bursts |
| Maximum Worker Processes | 1 | 1 — never use a web garden |
| Start Mode | OnDemand | AlwaysRunning (with App Initialization) |
Wrapping up
App-pool tuning for Acumatica is not exotic: turn off idle time-out, replace the rolling recycle with a fixed off-hours one, add a memory ceiling as a safety net, keep it to a single worker process, and warm the pool after every recycle. Do that and the "it's slow first thing in the morning" tickets mostly stop. When they don't, the pool is no longer the suspect and it is time to look at SQL and customization code — but rule the pool out first, because it is the cheapest thing to fix. If you are stuck on something specific, reach out or keep reading through the rest of the Acumatica blog.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.