The TIdTCPServer.OnDisconnect event is fired when the server thread that owns the socket is being shut down. There are 2 reasons I can think of for why that event might not happen when you are expecting it:
- if your server code is preventing TIdTCPServer from recognizing the disconnect so it can tell the appropriate thread to stop running. For instance, if your TIdTCPServer.OnExecute event handler swallows Indy exceptions from bubbling up the call stack. Remember, Indy uses exceptions to report errors, which includes when a peer disconnects while a blocking socket operation is in progress. If TIdCPServer catches an exception raised from its events, it will shut down the raising thread. So, if you are catching exceptions in your own code, make sure you re-raise any exception that is derived from EIdException, at least.
- if the disconnect is abnormal in such a way that the OS has not detected it yet, then it will not have been reported to Indy yet. Eventually, the OS will timeout internally and report errors on a lost connection, but that timeout is quite large, so it may take awhile. You can use timeouts in your own code to help avoid that. Either with Indy's own ReadTimeout properties and function parameters, or by enabling TCP keep-alives on the connection.

