Tune Windows Server TCP/IP and IIS

In this small post I'll guide you through the various Windows Server and IIS configuration settings, for an optimized network performance, high performance websites and high volume of web requests.
Published on Wednesday, 21 June 2023

When you have set up your ASP.NET / .NET or PHP configuration for high performing websites in Windows Server, it sometimes becomes important to reconfigure Windows Server's TCP/IP stack and IIS too. You may have to increase network throughput and performance, or you just might run out of available ports / sockets (aka port exhaustion). And, as you know, fast page loads are more and more important nowadays for seach engine optimization (SEO) and user experience. Therefore we’ll dive into tuning IIS and TCP/IP stack for high performance websites and high volume of web requests a bit.


In this small post I'll guide you through the various Windows Server and IIS configuration settings, for an optimized network performance, high performance websites and high volume of web requests.

This post is especially useful if you notice any of the following warning messages in your System eventlog:

A request to allocate an ephemeral port number from the global TCP port space has failed due to all such ports being in use.

and / or

TCP/IP failed to establish an outgoing connection because the selected local endpoint was recently used to connect to the same remote endpoint. This error typically occurs when outgoing connections are opened and closed at a high rate, causing all available local ports to be used and forcing TCP/IP to reuse a local port for an outgoing connection. To minimize the risk of data corruption, the TCP/IP standard requires a minimum time period to elapse between successive connections from a given local endpoint to a given remote endpoint.

Both have source Tcipip and have Event IDs 4231 and 4227.

IIS limits for a website

The limits element of the element configures settings that limit the amount of bandwidth, the number of connections, or the connection time-out for client requests to a site.

If the <limits> element is configured in both the <siteDefaults> section and in the <site> section for a specific site, the configuration in the <site> section is used for that site.

IIS Connection Timeout

IIS’ default Connection Timeout for HTTP requests is 120 seconds. This means that a connection will remain open for two minutes, even when the client has disconnected (e.g, clicked a link and left to a different website). You can safely reduce this to 60 or 30 seconds, depending on your needs, with AppCmd:

appcmd.exe set config `
  -section:system.applicationHost/sites `
  "/[name='example.com'].limits.connectionTimeout:00:01:00" `
  /commit:apphost 

Or globally for all sites:

appcmd.exe set config `
  -section:system.applicationHost/sites `
  /siteDefaults.limits.connectionTimeout:"00:01:00" `
  /commit:apphost
appcmd.exe set config `
  -section:system.applicationHost/webLimits `
  /connectionTimeout:"00:01:00" `
  /commit:apphost

Notice limits and webLimits. This releases sockets that are waiting in a TIME_WAIT state, faster because the <webLimits> element specifies TCP/IP connection and bandwidth limits, whereas the <limits> element configures default settings that limit the amount of bandwidth, the number of connections, or the connection time-out for client requests for a Web server.

You can get the number of current connections using PowerShell, listed per website if necessary.

IIS maxConnections

Use the following AppCmd command to increase -or decrease- the number of maximum number of connections for a site. Use this setting to limit the number of simultaneous client connections.

appcmd.exe set config `
  -section:system.applicationHost/sites `
  "/[name='example.com'].limits.maxConnections:1500" `
  /commit:apphost

Ephemeral ports

This one is important with Windows Server 2012 R2 and below, and became less imortant with newer Windows Server versions.

An ephemeral port is a communications endpoint, or port. The number of available ephemeral ports is limited and differs per Windows Server version. Please be aware of that and don't just type over commands supposed to increase the amount of available ports to resolve port exhaustion. You may end up lowering the ports availabe... Basicly you have 65535 ports and the first 1024 are reserved. Of the remaining 64511, Windows has a subset configured for use.

If we take a tour down memory lane, you may find KB929851, where you read:

To comply with Internet Assigned Numbers Authority (IANA) recommendations, Microsoft has increased the dynamic client port range for outgoing connections in Windows Vista and Windows Server 2008. The new default start port is 49152, and the new default end port is 65535. This is a change from the configuration of earlier versions of Windows that used a default port range of 1025 through 5000.

To look up the default for your Windows Server version, use the netsh.exe command:

netsh int ipv4 show dynamicport tcp
netsh int ipv4 show dynamicport udp
netsh int ipv6 show dynamicport tcp
netsh int ipv6 show dynamicport udp

My Windows 11 workstation returns:

PS C:\Users\Jan Reilink> netsh int ipv4 show dynamicport tcp

Protocol tcp Dynamic Port Range
---------------------------------
Start Port      : 49152
Number of Ports : 16384

PS C:\Users\Jan Reilink> netsh int ipv4 show dynamicport udp

Protocol udp Dynamic Port Range
---------------------------------
Start Port      : 49152
Number of Ports : 16384

PS C:\Users\Jan Reilink> netsh int ipv6 show dynamicport tcp

Protocol tcp Dynamic Port Range
---------------------------------
Start Port      : 49152
Number of Ports : 16384

PS C:\Users\Jan Reilink> netsh int ipv6 show dynamicport udp

Protocol udp Dynamic Port Range
---------------------------------
Start Port      : 49152
Number of Ports : 16384

And as you can see my old Windows Server 2012 R2 VM has the same ports configured:

PS C:\Windows\system32> Get-ComputerInfo | Select-Object OSName,OSVersion

OsName                                    OsVersion
------ ---------
Microsoft Windows Server 2012 R2 Standard 6.3.9600


PS C:\Windows\system32> netsh int ipv4 show dynamicport tcp

Protocol tcp Dynamic Port Range
---------------------------------
Start Port      : 49152
Number of Ports : 16384

PS C:\Windows\system32> netsh int ipv4 show dynamicport udp

Protocol udp Dynamic Port Range
---------------------------------
Start Port      : 49152
Number of Ports : 16384

PS C:\Windows\system32> netsh int ipv6 show dynamicport tcp

Protocol tcp Dynamic Port Range
---------------------------------
Start Port      : 49152
Number of Ports : 16384

PS C:\Windows\system32> netsh int ipv6 show dynamicport udp

Protocol udp Dynamic Port Range
---------------------------------
Start Port      : 49152
Number of Ports : 16384

Long story short: do your investigations first before you make reckless changes. If, and only if, you need to increase this MaxUserPort configuraton, read on.

The TCP MaxUserPort configuration is something different than IIS' MaxUrlLength, keep this in mind.

MaxUserPort

The number of available short-lived (or ephemeral) ports differs per Windows Server version. In the early Windows 2003 days, ephemeral ports are allocated between the values of 1024 and 5000 inclusive. The MaxUserPort value controls the maximum port number used when an application requests any available user port from the system. You could increase this in the Windows Registry, by adding the MaxUserPort key in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters.

For example:

reg.exe `
  add HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters `
  /v MaxUserPort `
  /t REG_DWORD `
  /d 0x000067c0

This sets an value 0x000067c0 (26560) for MaxUserPort in the registry. A reboot is required to take this into effect.

Starting from Windows Server 2008 you can use netsh.exe to configure a Dynamic Port Range.

Dynamic Port range

On Windows 2008 and 2012 we use the Network Shell (netsh) to determine a dynamic port range. Its default setting is (as shown above):

C:\Users\Jan Reilink> netsh int ipv4 show dynamicportrange tcp

Protocol tcp Dynamic Port Range
---------------------------------
Start Port      : 49152
Number of Ports : 16384

You can increase this by -for example- roughly 9152 extra ephemeral ports:

netsh int ipv4 set dynamicportrange protocol=tcp startport=40000 numberofports=25536 store=persistent

Again, a reboot is required to take this in effect.

TCPTimedWaitDelay

The registry value TCPTimedWaitDelay in Windows Server 2012 determines how long a closed port waits until the closed port can be reused. This defaults to 240 seconds and can be decreased to 30 seconds. The TcpTimedWaitDelay DWORD (32-bit) Value name is also found under HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters. As is MaxUserPort mentioned above.

Set it’s value to 3c hexadecimal for a 60 second TIME_WAIT window. Again an example:

reg.exe `
  add HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters `
  /v TCPTimedWaitDelay `
  /t REG_DWORD `
  /d 0x0000003c

Bonus tip: convert hexadecimal values to decimal in PowerShell:

PS C:\Users\Jan Reilink> [uint32]"0x000067c0"
26560
PS C:\Users\Jan Reilink> [uint32]"0x3c"
60

Easy, right? :)

Disable ECN Capability in Windows Server 2012

If you are on Windows Server 2012, you must not forget to disable explicit congestion notification (ECN, or ECN Capability). This really slows down outbound connections to some outdated, or faulty, network equipment.

Disabling ECN Capability can improve your outbound connection speed.

TCP Chimney Offload

TCP Chimney Offload is a networking technology that helps transfer the workload from the CPU to a network adapter during network data transfer. In Windows Server, TCP Chimney Offload enables the Windows networking subsystem to offload the processing of a TCP/IP connection to a network adapter that includes special support for TCP/IP offload processing.

TCP Chimney Offload is available in all versions of Windows Server 2008 and 2012. Both TCP/IPv4 connections and TCP/IPv6 connections can be offloaded if the network adapter supports this feature.

Configure TCP Chimney Offload in the operating system

netsh int tcp set global chimney=enabled

In some rare circumstances, enabling TCP Chimney Offload might degrade performance. Maybe due to bad network interface card (NIC) firmware or drivers. Then you can disable TCP Chimney Offload:

netsh int tcp set global chimney=disabled

Frequently Asked Questions (FAQs)

What are some error messages I can expect when my system suffers from port exhaustion?

Some of the error messages indicating port exhaustion might be:

"An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full. (example.com:443). Retrying until reconnected."

or

"A request to allocate an ephemeral port number from the global TCP port space has failed due to all such ports being in use."

or

"TCP/IP failed to establish an outgoing connection because the selected local endpoint was recently used to connect to the same remote endpoint. This error typically occurs when outgoing connections are opened and closed at a high rate, causing all available local ports to be used and forcing TCP/IP to reuse a local port for an outgoing connection. To minimize the risk of data corruption, the TCP/IP standard requires a minimum time period to elapse between successive connections from a given local endpoint to a given remote endpoint."

Conclusion tuning (older) Windows Server TCP/IP stack and IIS for high performance websites and high volume of web requests

Out of the box, Windows Server and IIS are pretty optimized for high performance networking nowadays. See for example the default availability of HTTP/3 in Windows Server 2022. On older Windows versions however, you may need to make some configuration changes and tweaks to make Windows handle more network connections. But as always, measure first, make a change and measure again. Otherwise you don't know if a change made an improvement.

And don't forget this article was first written for Windows Server 2003, 2008 (R2) and Windows Server 2012.

Please note that this is a repost of an older (old) post of mine that I had removed. Want the original? Look it up at the Wayback machine. I repost this because parts are still important for high performing websites and webservers. Optimized network performance in Windows Server.

Cheers!