By default, each IIS application pool runs as a virtual account named IIS AppPool\<PoolName>. This account is NOT in the IIS_IUSRS group by default in IIS 7.5+. You must grant the virtual account (or IIS_IUSRS if you prefer) at minimum Read & Execute on the website physical path. The most common IIS permission error is deploying a site without granting the pool identity read access to the site root. The symptom is HTTP 500.19 (config read error) or HTTP 403 (access denied to content).
File System, Processes, and Services
Master NTFS permissions, understand the Windows process model, and learn how Windows Services interact with IIS — critical for diagnosing permission errors, process crashes, and service dependency failures.
🧒 Simple Explanation (ELI5)
The file system is like a filing cabinet. NTFS puts locks on every drawer and folder, and only people with the right key (permissions) can open them. Processes are like chefs in a kitchen — each one has its own station, ingredients, and job. Services are chefs who work the night shift — they start automatically and keep running even when nobody is logged in.
🔧 Why Do We Need It?
- Most IIS errors are permission errors: 401, 403, and 500.19 errors are almost always NTFS or application pool identity permission failures against the website root or config file.
- Process isolation for stability: each IIS app pool runs in a separate w3wp.exe process — understanding processes tells you why one site's crash doesn't kill others.
- Service dependencies determine boot order: IIS depends on WAS which depends on HTTP.sys — if you don't know the dependency chain, you won't understand why IIS refuses to start after a server reboot.
- Log file access: IIS writes logs to the filesystem under C:\inetpub\logs — file system knowledge tells you how to read, rotate, and troubleshoot them safely.
🌍 Real-world Analogy
Imagine a hospital. The NTFS file system is the badge-access door system — each room requires a specific role badge to enter (read, write, execute). Processes are individual doctors and nurses doing their assigned task. Windows Services are machines like the MRI scanner that run 24/7 without a human operating them, starting automatically when the hospital opens (server boots).
⚙️ Technical Explanation
NTFS (New Technology File System) is Windows' primary file system, providing file-level security via Access Control Lists (ACLs). Every file and folder has a Security Descriptor containing a DACL (Discretionary ACL) — the list of who can do what — and a SACL (System ACL) for auditing. Permissions stack: Allow overrides Deny at the same inheritance level, but explicit Deny on a file overrides inherited Allow. NTFS permissions are separate from Share permissions; on a local path, only NTFS applies. Key IIS-related identities: IIS_IUSRS (built-in group for all worker processes), IUSR (the anonymous request identity), and the application pool identity (by default a virtual account like IIS AppPool\DefaultAppPool).
Windows Processes are managed by the Process Manager in the NT kernel. Each process has its own virtual address space, token (security context), and handle table. Key fields visible in Task Manager or Process Explorer: Image (executable), PID (unique numeric ID), Session (0 = services, 1+ = interactive), User (security identity), CPU, and Memory — Working Set vs. Private Bytes vs. Virtual Bytes. For IIS, w3wp.exe processes are worker processes hosted inside a Windows Job object created by WAS, which enforces CPU and memory limits set on the application pool.
Windows Services are long-running processes managed by the Service Control Manager. They have four key states: Stopped, Starting, Running, Stopping. Services can be configured to auto-restart on failure (Recovery tab). Services run in designated sessions: most run in Session 0 (non-interactive) as NETWORK SERVICE, LOCAL SYSTEM, LOCAL SERVICE, or a managed service account (MSA/gMSA).
📊 Visual Representation
⌨️ Commands / Syntax
# --- NTFS Permissions --- # View permissions on a folder (cmd) icacls C:\inetpub\wwwroot\MyApp # Grant AppPool identity read access to site root icacls C:\inetpub\wwwroot\MyApp /grant "IIS AppPool\MyAppPool:(OI)(CI)RX" # OI = Object Inherit, CI = Container Inherit, RX = Read & Execute # Reset to default inherited permissions icacls C:\inetpub\wwwroot\MyApp /reset /T # --- Processes --- # List all processes with PID and username tasklist /v | findstr "w3wp" # Kill a process by PID taskkill /PID 1234 /F # Map w3wp.exe PID to AppPool (must run as admin) %windir%\system32\inetsrv\appcmd list wp # Take a memory dump of a w3wp.exe (requires ProcDump from Sysinternals) procdump -ma 1234 C:\dumps\w3wp_dump.dmp # --- Services --- # Query service status sc query w3svc sc query was sc query http # Start / Stop / Restart a service net start w3svc net stop w3svc sc stop w3svc ; sc start w3svc # View service recovery settings sc qfailure w3svc # List service dependencies sc enumdepend http 4096
💼 Example (Real-world Use Case)
A DevOps team deploys a new ASP.NET API to an IIS server. The site immediately returns HTTP 500.19 with sub-status code 0x80070005 (Access Denied). The engineer runs icacls C:\inetpub\wwwroot\api and confirms the folder ACL was set by the deployment pipeline to grant only BUILTIN\Administrators access. The IIS app pool identity (IIS AppPool\api-pool) is not in that group and has no explicit entry. The fix: icacls C:\inetpub\wwwroot\api /grant "IIS AppPool\api-pool:(OI)(CI)RX". The site serves requests within seconds.
🧪 Hands-on
- Right-click
C:\inetpub\wwwroot→ Properties → Security tab. Confirm thatIIS_IUSRSandIUSRappear in the ACL with at minimum Read & Execute permissions. - Open PowerShell as Administrator and run
icacls C:\inetpub\wwwroot. Note the permission flags for each identity. Identify the AppPool identity entries if any IIS sites exist. - Open Task Manager → Details tab. Find all running
w3wp.exeprocesses. Note their PIDs and usernames (they should show asIIS AppPool\<PoolName>). - Run
%windir%\system32\inetsrv\appcmd list wpto map each w3wp.exe PID to its application pool name. - Open Services.msc and find "World Wide Web Publishing Service". Check its dependencies by right-clicking → Properties → Dependencies tab. Confirm W3SVC depends on WAS, and WAS depends on HTTP (the kernel driver).
The default IIS AppPool identity is a virtual account — it exists only on the local machine and cannot be used for network authentication (domain resource access). If your application needs to access a SQL Server over the network using Windows Authentication, configure the app pool to run as a group Managed Service Account (gMSA). gMSAs have automatic password rotation, work across servers in a cluster, and can be granted database permissions in SQL Server directly — the recommended approach for production IIS deployments connecting to domain resources.
🐛 Debugging Scenario
Failure: After deploying a new IIS site, the application runs fine when accessed locally on the server but throws "Access to path denied" exceptions in the application log when accessed remotely.
- The local test was run as administrator — a privileged user, bypassing normal ACL checks. Remote access goes through the IIS app pool identity, which is
IIS AppPool\NewSite. - Run
icacls C:\inetpub\wwwroot\NewSite /T. Check if any subdirectory (e.g., App_Data, logs, uploads) is missing the AppPool identity in its ACL. - The app writes temporary files to
C:\Windows\Temp. The virtual account lacks write access there. Solution: grant Write permission to the AppPool identity on that path, or configure the app to write to the site's own temp directory which it already owns. - Pro tip: use Process Monitor (Sysinternals) to trace all filesystem ACCESS DENIED events in real time and immediately identify which file path is causing the error.
🎯 Interview Questions
Beginner
NTFS (New Technology File System) is Windows' enterprise file system supporting file-level security (ACLs), file compression, encryption (EFS), disk quotas, symbolic links, sparse files, and volume sizes up to 16 exabytes. FAT32 is an older, simpler file system with no security (no per-file permissions), a maximum file size of 4 GB, and a maximum partition size of 32 GB when formatted from Windows. IIS must be hosted on NTFS volumes — FAT32 cannot enforce the access control required for secure web hosting.
A process is an instance of a running program. It holds: a virtual address space (private memory region isolated from other processes), a security token (determines what the process is allowed to do), open handles (references to kernel objects like files and registry keys), one or more threads (the actual units of CPU execution), and environment variables. The process is the unit of isolation — when a process crashes, only its resources are released; other processes continue unaffected.
A process is a container with its own memory space and security context. A thread is an execution path within a process that shares the process's memory. A process has at least one thread (the initial/main thread) and can have many more. Threads within the same process can communicate directly through shared memory, while communication between processes requires inter-process communication (IPC) mechanisms like pipes, sockets, or memory-mapped files. IIS worker processes (w3wp.exe) are multi-threaded — each incoming request is handled on a thread from the IIS thread pool.
A Windows Service is a long-running background process managed by the Service Control Manager. Unlike regular applications, services: run without a logged-in user (in Session 0); start automatically at boot; can be configured to restart themselves on failure; cannot display UI to users (Session 0 isolation); and are controlled via sc.exe, net.exe, services.msc, or PowerShell. W3SVC and WAS are both Windows Services — they start when the server boots and run until or unless stopped, regardless of who is or isn't logged in.
IIS_IUSRS is a built-in local Windows group that IIS uses to group all application pool identities. In older versions of IIS (before 7.5), you had to manually add the NETWORK SERVICE account to this group. In IIS 7.5 and later, all application pool virtual accounts are automatically added as members at runtime — meaning you can grant IIS_IUSRS permission on a folder and all app pools will have that permission without individually listing each pool identity.
Intermediate
NTFS permissions are inherited from parent folders by default. A child folder receives all Allow and Deny entries from its parent unless inheritance is explicitly broken. You break inheritance when: a subdirectory needs stricter permissions (e.g., an admin-only config folder within a publicly readable web root); or a folder needs broader permissions than its parent. To break inheritance, open Advanced Security Settings → Disable Inheritance → choose to Copy or Remove inherited entries. After breaking, the folder's ACL is explicit and changes to the parent ACL will no longer propagate to it. In IIS, the App_Data folder commonly has inheritance broken to restrict anonymous web access while the IIS identity retains write access for session storage.
A Job Object is a kernel container that groups processes and enforces shared resource limits. IIS's Windows Process Activation Service (WAS) creates a Job Object for each application pool and assigns the pool's worker process (w3wp.exe) to it. The Job Object enforces CPU rate limits, memory limits (configured on the app pool's "Maximum Private Memory" setting), and process lifetime. This is why IIS can automatically recycle a worker process when it exceeds a memory threshold — WAS monitors the Job Object's counters and triggers a recycle when a limit is hit.
LOCAL SYSTEM: highest privilege, can do almost anything on the local machine including accessing network resources as the computer account. Avoid for IIS pools — too much privilege. NETWORK SERVICE: lower privilege, can access network resources using computer account credentials. Used for older IIS worker processes. LOCAL SERVICE: lower privilege still, cannot use network with computer credentials. Only for services needing minimal local access. Virtual Accounts (IIS AppPool\Name): IIS-specific, no password management required, lowest privilege, cannot be used for domain resource access. gMSA (Group Managed Service Account): domain-integrated, automatic password rotation, can access network resources, best choice for production IIS pools needing database or file share access.
IUSR is the built-in anonymous authentication account for IIS. When a browser makes a request without sending credentials and the site uses Anonymous Authentication, IIS processes the file access request using the IUSR account token. IUSR replaced the old IUSR_MachineName account from IIS 6. It is a built-in low-privilege account — it should have Read & Execute on static web content but never Write on any path. If anonymous authentication is disabled (e.g., Windows Authentication only), IUSR is not used at all — requests are processed as the authenticated user's token via impersonation.
NTFS SACL (System ACL) enables auditing. Right-click the file → Properties → Security → Advanced → Auditing tab → Add an audit entry. Choose which accounts to audit and which operations (Success/Failure for Read, Write, Delete, etc.). Enable Object Access auditing in Local Security Policy (or Group Policy) under Security Settings → Advanced Audit Policy → Object Access. Once enabled, accesses to that file are logged to the Security event log as event ID 4663. For web.config or applicationHost.config, auditing Write and Delete attempts is a good security practice to detect unauthorised configuration changes.
Scenario-based
Virtual accounts (IIS AppPool\Name) are distinct per pool. IIS AppPool\MyApp and IIS AppPool\NewSite are two separate security principals. Granting access to one does not grant it to the other. Three solutions: (1) Grant the IIS_IUSRS group Write access to C:\uploads — this automatically covers all virtual account pools. (2) Grant each pool identity explicitly: icacls C:\uploads /grant "IIS AppPool\NewSite:(OI)(CI)M". (3) Configure both pools to run as the same gMSA and grant the gMSA write access — the cleanest approach for shared-resource scenarios in production.
Take a memory dump first without killing the process: procdump -ma <PID> C:\dumps\dump.dmp. This captures the full memory snapshot. While doing this, check: Task Manager's "Working Set" vs "Private Bytes" — working set can be large due to file cache; private bytes is the real application memory. Review app pool recycling settings — does it have a Maximum Private Memory limit set? If not, configure one as an emergency guard. Analyse the dump file with WinDbg + SOS extension or send to the app team to identify which managed heap objects are accumulating (likely a memory leak in the application code). Plan a rolling recycle during low-traffic period to restore memory without session loss if ARR (Application Request Routing) or session state is configured for persistence.
Open services.msc → right-click the service → Properties → Recovery tab. Set: First failure = Restart the Service, Second failure = Restart the Service, Subsequent failures = Restart the Service. Set "Reset fail count after" to 1 day. Set "Restart service after" to 1 minute. Click Apply. Alternatively via command line: sc failure <ServiceName> reset= 86400 actions= restart/60000/restart/60000/restart/60000. Additionally, check the Event Viewer Application and System logs to find WHY the service is stopping — auto-restart is a mitigation, not a fix. Check for access denied errors, missing dependencies, or corrupt configuration as the root cause.
Apply least-privilege: Site root (e.g., C:\inetpub\wwwroot\MyApp): Read & Execute for AppPool identity — allows IIS to read HTML, JS, CSS, DLLs, and web.config. Bin folder (C:\inetpub\wwwroot\MyApp\bin): Read & Execute — DLLs must be readable but not modifiable by the web process. App_Data (session state, SQLite DBs): Read, Write, Modify — only if the application actually writes here. Log folder (if app writes its own logs): Write, Modify. Temp/upload folder: Modify (not FullControl). System paths (C:\Windows\Temp, C:\Windows\Microsoft.NET\Framework): typically requires no explicit grants in modern .NET — avoid adding unnecessary permissions here. Never grant FullControl to AppPool identities on web directories.
Check the service dependency chain first: WAS must be running before W3SVC can start. Run sc query was. If WAS is stopped, check why: sc query http — if HTTP.sys failed to load, WAS cannot start. Check Event Viewer System log for errors from: W3SVC, WAS, HttpEvent, or tcpip. Common causes: HTTP.sys failed because another process bound to port 80 (run netstat -ano | findstr :80 to find the conflicting process), or Windows Firewall base filtering engine stopped which blocks HTTP.sys initialisation. Fix the dependency, then start services in order: http driver → WAS → W3SVC, or simply run iisreset /start which handles the correct order.
🌐 Real-world Usage
NTFS permissions and process model understanding are used every day by Windows Server administrators and IIS support engineers — from setting up deployment pipelines that correctly provision permissions, to troubleshooting permission errors in production without giving away excessive access. The service dependency knowledge is essential during incident response when infrastructure comes back up after a datacenter power event or planned maintenance.
📝 Summary
NTFS ACLs control who can read, write, and execute files — most IIS errors trace back to incorrect permissions on the site root or config file. IIS worker processes run as virtual account identities; each app pool is isolated in its own process. W3SVC → WAS → HTTP.sys form the dependency chain — understand this or IIS startup failures will remain mysterious.