MaxUserPort and TcpTimedWaitDelay: Fixing Port Exhaustion on Windows Server

MaxUserPort and TcpTimedWaitDelay: Fixing Port Exhaustion on Windows Server

Updated October 2026 for current Windows Server versions.

If a Windows server suddenly can’t open new outbound connections, while CPU, memory and the network all look fine, you may be running out of ephemeral (dynamic) ports. This is called port exhaustion. It typically hits busy application servers, proxies, web servers that call back-end APIs, and anything that opens many short-lived TCP connections.

This guide explains how to confirm the problem, what MaxUserPort and TcpTimedWaitDelay actually do, the right way to change them on modern Windows Server, and how to fix the root cause.

How port exhaustion happens

Every outbound TCP connection uses a local port taken from the dynamic port range. When the connection closes, the side that closed it keeps the port in the TIME_WAIT state for a while, so late packets from the old connection can’t be confused with a new one. If an application opens and closes connections faster than ports leave TIME_WAIT, the pool empties and new connections fail.

On Windows Server 2008 and later, the default dynamic range is 49152–65535, which is 16,384 ports per IP address and protocol.

Symptoms

  • Intermittent connection failures from the server to databases, APIs or other servers, while inbound traffic still works.
  • Application errors such as “Only one usage of each socket address is normally permitted” or socket error 10048 / WSAEADDRINUSE, or 10055 / WSAENOBUFS.
  • In the System event log, Event ID 4227 (Tcpip) about a recently used local endpoint, or Event ID 4231 saying an ephemeral port could not be allocated because all ports are in use.
  • The problem often clears by itself after a few minutes, or after restarting the application, then comes back under load.

Step 1: Confirm the problem

Check the current dynamic port range:

netsh int ipv4 show dynamicport tcp

Count connections by state. A very large number in TimeWait (thousands, close to the size of the port range) points to exhaustion:

Get-NetTCPConnection | Group-Object -Property State | Sort-Object Count -Descending | Format-Table Count, Name -AutoSize

Find which process is using the most ports:

Get-NetTCPConnection |
  Group-Object -Property OwningProcess |
  Sort-Object Count -Descending |
  Select-Object -First 10 Count, @{n='Process';e={(Get-Process -Id $_.Name -ErrorAction SilentlyContinue).ProcessName}}, Name

Check which remote server and port the connections go to, which usually reveals the misbehaving integration:

Get-NetTCPConnection -State TimeWait |
  Group-Object -Property RemoteAddress, RemotePort |
  Sort-Object Count -Descending |
  Select-Object -First 10 Count, Name

Step 2: Understand MaxUserPort and TcpTimedWaitDelay

MaxUserPort

MaxUserPort is a registry value that set the highest dynamic port on old Windows versions such as Windows Server 2003, where the default range was only 1025–5000. On Windows Server 2008 and newer it is no longer the right tool. The dynamic range is managed with netsh instead, as shown below. Many old articles still recommend MaxUserPort, which is why it causes confusion.

TcpTimedWaitDelay

TcpTimedWaitDelay controls how long a closed connection stays in TIME_WAIT before its port can be reused. It lives here:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
TcpTimedWaitDelay (REG_DWORD), value in seconds, valid range 30–300

On current Windows versions the default is 120 seconds when the value isn’t set. Lowering it, for example to 30, frees ports up to four times faster.

Step 3: Increase the dynamic port range (modern Windows)

Before widening the range, check that no installed service needs a port inside the new range, and list the ranges Windows has reserved:

netsh int ipv4 show excludedportrange protocol=tcp

Then set a larger range. This example uses ports 10000–65535, which gives 55,536 ports:

netsh int ipv4 set dynamicport tcp start=10000 num=55536
netsh int ipv6 set dynamicport tcp start=10000 num=55536

Verify the change:

netsh int ipv4 show dynamicport tcp

Be careful: if an application or service listens on a fixed port inside the new range, Windows may hand that port out to an outbound connection first, and the service then fails to start. Reserve such ports with netsh int ipv4 add excludedportrange protocol=tcp startport=<port> numberofports=1, or choose a range that avoids them.

Step 4: Shorten TIME_WAIT (optional)

Run in an elevated PowerShell window:

New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters' `
  -Name 'TcpTimedWaitDelay' -PropertyType DWord -Value 30 -Force

Restart the server for the change to take effect. Don’t go below 30 seconds; Windows doesn’t accept lower values.

Step 5: Fix the root cause

Bigger ranges and shorter timeouts buy time, but the real fix is usually in the application:

  • Reuse connections instead of opening a new one per request. For example, in .NET reuse a single HttpClient (or use IHttpClientFactory) rather than creating and disposing one for each call.
  • Use connection pooling for databases and enable HTTP keep-alive.
  • Spread the load: if a server legitimately needs a very high number of outbound connections to one destination, add more source IP addresses or scale out to more servers.
  • Monitor: track the number of TIME_WAIT connections, for example with Performance Monitor or a scheduled PowerShell check, so you see the problem before users do.

Quick checklist

  1. Confirm with Get-NetTCPConnection that TIME_WAIT connections are piling up, and find the process.
  2. Check excluded and reserved ports, then widen the dynamic range with netsh.
  3. Optionally set TcpTimedWaitDelay to 30 and restart.
  4. Fix connection reuse in the application.
  5. Add monitoring.

Have a port exhaustion case that doesn’t fit this pattern? Get in touch.

Share this content:

Leave a Reply