Writing
Two Python Servers Listened on the Same Port on Windows and the Requests Split Between Them
SO_REUSEADDR is on by default in http.server, and on Windows that lets a second process bind a port that is already being listened on.
Writing
SO_REUSEADDR is on by default in http.server, and on Windows that lets a second process bind a port that is already being listened on.
Notes
The symptom was a record that got created and then was not in the list. Create returns 200, read returns an empty array, refresh does not help. That looks exactly like a logic bug, and I went looking for one.
There was no logic bug. Three copies of the same server script were listening on port 8391 at the same time, and Windows had let all three bind.
sets by default, which sets on the socket. On Linux that option mostly means you can rebind a port still sitting in TIME_WAIT. It does not let two live listeners share a port.
On Windows it does. Microsoft's own documentation is direct about it:
"The SO_REUSEADDR socket option allows a socket to forcibly bind to a port in use by another socket... Once the second socket has successfully bound, the behavior for all sockets bound to that port is indeterminate."
And further down, about which socket gets the traffic:
"the second bind call will 'hijack' the port and the application will be unable to determine which of the two sockets received specific packets sent to the 'shared' port."
The behaviour table for Windows Server 2003 and later shows the exact case Python puts you in. First socket with on the wildcard address, second socket also with on the wildcard address, same user account: Success. No error, no warning. Microsoft also notes that no special privileges are required to use the option.
The servers each had their own data directory. So one process wrote the new record to its own database, and the next request landed on a different process that read a different database and answered honestly that there was nothing there.
The distribution is not round robin and not predictable, which is why it feels like a race in your own code. Measured on 10 September 2026: three listeners on 8391, the write endpoint hitting one store and the read endpoint hitting another.
The reason this costs hours is that the symptom is a perfect imitation of an application bug, and every instinct says to read the handler.
Before you restart a test server, confirm the old one is actually dead. If you are in Git Bash on Windows, will often report success and kill nothing, because it is not seeing the Windows process the way you think it is.
What works:
then confirm the port is quiet:
That should return nothing. Keep the filter narrow. A pattern like will also kill unrelated things you have running, and I have done that too.
A cheaper habit is to give each test run its own port, so a leftover process cannot share one with you.
If you own the server code and it is a real service rather than a scratch test server, the proper answer is . Microsoft's guidance on that is not hedged: all server applications should set it, both to prevent hijacking and so that binding fails loudly when something else already holds the port. A bind that fails is a much better morning than a bind that succeeds twice.
More