MaxUserPort - what it is, what it does, when it's important

What can we say about MaxUserPort that hasn't already been said? Not a lot, it would seem. He's a beautiful dancer, perhaps? Ahh, such gentle humour, and nary a kitten drowned anywhere.

But TCP port shenanigans are fairly frequently misunderstood, so let's talk about the very basics of MaxUserPort.

NB: This is all pre-Vista behaviour - applicable from NT4 through to Windows Server 2003, including all the little NT-flavoured stops on the way.

NB 2 [2016-11-04]: But! The same principles apply to Windows Vista through to Windows 10 / Server 2016, and the MaxUserPort value seems to be supported, presumably for "legacy" purposes (eg, an app installer sets it, and it's honoured), sooo... it should still work similarly. I think. YMMV. Always test. Hugs.

MaxUserPort controls "outbound" TCP connections

MaxUserPort is used to limit the number of dynamic ports available to TCP/IP applications. (I don't know why , I just know it is . Probably something to do with constraining resource use on 16MB machines, or something.)

It's never going to be an issue affecting inbound connections.

MaxUserPort is not the right answer if you think you have an inbound connection problem.

To further simplify: MaxUserPort is typically going to limit the number of outbound sockets/connections that can be created.

Note: that's really a big fat generalization, but it's one that works in 99% of cases.

If an application asks for the next available socket (a socket is a combination of an IP address and a port number), it'll come from the ephemeral port range allowed by MaxUserPort. Typically, these "next available" sockets are used for outbound connections.

The default unmodified range for MaxUserPort pre-Vista was from 1024-5000 (so ~4000 ports), but the possible range - when modified - is up to 65534.

(Vista+ default ephemperal port range is 49000-65535, so 3x the ports. See this.)


Value Type: DWORD
Valid Range: 5000-65534 (decimal)
Default: 0x1388 (5000 decimal - when not set - see the notes for MS08-037 for an update on pre-Vista behaviour)

When You Fiddle MaxUserPort

So, why would you change MaxUserPort?

In the web server context (equally applicable to other application servers or even client programs), you'd usually need to look at MaxUserPort when:

- your server process is communicating with some type of other system {as a client}  (like a back-end database, or any TCP-based application server - quite often http web servers)


- you are not using socket pooling , and/or

- your request model is something like one request = one outbound TCP connection (or more!)

In this type of scenario, you can run out of ephemeral ports (between 1024 and MaxUserPort) very quickly, and the problem will scale with the load applied to the system , particularly if a socket is acquired and abandoned with every request.

When a socket is abandoned, it'll (by default) take two minutes to fall back into the pool.

Discussions about how the application/website design could scale better if it reused sockets rather than simply throwing new connections at each request tend to be unwelcome when the users are screaming that the app is slow, or hung, or whatever, so at this point, you'd probably have established that new request threads are hung waiting on an available socket, and just turn up MaxUserPort to 65534 and then hope your app doesn't hit that as the next scale limiter.


What Next? TcpTimedWaitDelay, natch

Once MaxUserPort is at 65534, it's still possible for the rate of port use to exceed the rate at which they're being returned to the pool! You've bought yourself some headroom, though.

So how do you return connections to the pool faster ?

Glad you asked! - you start tweaking TcpTimedWaitDelay .

By default, a connection can't be reused for 2 times the Maximum Segment Lifetime (MSL), which works out to 4 minutes, or so the docs claim , but according to The Lore O' The Group here, we reckon it's actually just the TcpTimedWaitDelay value, no doubling of anything.

TcpTimedWaitDelay lets you set a value for the Time_Wait timeout manually.

As a quick aside: the value you specify has to take retransmissions into account - a client could still be transferring data from a server when a FIN is sent by the server, and the client then gets TcpTimedWaitDelay seconds to get all the bits it wants. This could be sucky in, for example, a flaky dial-up networking scenario, or, say, New Zealand, if the client needs to retransmit a whole lot... and it's sloooow. (and this is a global option, as far as I remember).

30 seconds is a nice, round number that either quarters or eighths (depending on who you ask - we say quarter for now) the time before a socket is reusable (without the programmer doing anything special (say, SO_REUSEADDR)).

If you've had to do this, at this point, you should be thinking seriously about the architecture - will this scale to whatever load requirements you have ?

The maths is straightforward:

If each connection is reusable after a minimum of N (TcpTimedWaitDelay) seconds,
and you are creating more than X (MaxUserPort) connections in an N second period...

Your app is going to be spending time "waiting" on socket availability...

(Which is what techy types call "blocking" or "hanging". Nice*!)

Fun* KB Articles: Event ID 4227