How to Configure and Reduce TCP Established Connection Timeout in Windows for Robust Database Applications


3 views

When a client application (like Firebird DB client) crashes or gets terminated abruptly while maintaining a TCP connection to port 3050, Windows servers may keep showing the connection as ESTABLISHED in netstat output - even after client termination or power-off. This isn't specific to Firebird but a fundamental TCP behavior in Windows.

Windows maintains TCP connections in ESTABLISHED state until:

  • Receiving a proper FIN or RST packet
  • TCP keepalive mechanism detects the failure
  • System-wide timeout thresholds are reached

The most relevant registry values (all in milliseconds):

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters]
"KeepAliveTime"=dword:000927c0  ; Default 9,000,000ms (2.5 hours)
"KeepAliveInterval"=dword:000003e8  ; Default 1,000ms (1 sec)
"MaxDataRetransmissions"=dword:00000005  ; Default 5 retries

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{your-interface-guid}]
"TcpMaxDataRetransmissions"=dword:00000003  ; Per-interface override

For Firebird specifically (and similar database clients), consider these approaches:

// C# example for setting TCP keepalive programmatically
public void SetTcpKeepAlive(Socket socket, int keepAliveTime, int keepAliveInterval)
{
    byte[] inValue = new byte[12];
    BitConverter.GetBytes((uint)1).CopyTo(inValue, 0); // enable
    BitConverter.GetBytes((uint)keepAliveTime).CopyTo(inValue, 4);
    BitConverter.GetBytes((uint)keepAliveInterval).CopyTo(inValue, 8);
    
    socket.IOControl(IOControlCode.KeepAliveValues, inValue, null);
}

// Usage for a Firebird connection:
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
SetTcpKeepAlive(socket, 30000, 5000); // 30s timeout, 5s interval

For Windows Server hosting database services:

  1. Set KeepAliveTime to 300000 (5 minutes) for faster dead connection detection
  2. Configure firewall to drop half-open connections after timeout
  3. Implement application-level heartbeat if possible

Use these PowerShell commands to verify current settings:

Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters" | 
Select-Object KeepAliveTime, KeepAliveInterval, MaxDataRetransmissions

# Check established connections with timers
Get-NetTCPConnection -State Established | 
Where-Object {$_.LocalPort -eq 3050} | 
Select-Object Local*,Remote*,State,@{Name="Timer";Expression={$_.OffloadState}}

When dealing with TCP connections in Windows, you might encounter situations where terminated clients still show as ESTABLISHED in netstat. This occurs because Windows maintains the connection state until it detects the failure through its timeout mechanism.

Windows uses a combination of keepalive packets and retransmission timeouts to detect dead connections. The default values are:

  • Initial retransmission timeout (RTO): 3 seconds
  • Maximum retransmission timeout: 30 seconds
  • Keepalive interval: 2 hours

You can adjust these parameters through registry settings or programmatically:

Registry Modification

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters]
"KeepAliveTime"=dword:000927c0
"KeepAliveInterval"=dword:000003e8
"TcpMaxDataRetransmissions"=dword:00000005

Programmatic Configuration (C# Example)

using System;
using System.Net.Sockets;
using System.Runtime.InteropServices;

class TcpTimeoutConfig
{
    [DllImport("iphlpapi.dll", SetLastError = true)]
    private static extern uint SetTcpEntry(IntPtr pTcpTable);

    public static void SetTcpConnectionTimeout(Socket socket, uint timeout)
    {
        var tcpRow = new MIB_TCPROW();
        tcpRow.dwState = (uint)TcpState.Established;
        tcpRow.dwLocalAddr = (uint)socket.LocalEndPoint.AddressFamily;
        tcpRow.dwLocalPort = (uint)((IPEndPoint)socket.LocalEndPoint).Port;
        tcpRow.dwRemoteAddr = (uint)socket.RemoteEndPoint.AddressFamily;
        tcpRow.dwRemotePort = (uint)((IPEndPoint)socket.RemoteEndPoint).Port;
        
        IntPtr ptr = Marshal.AllocCoTaskMem(Marshal.SizeOf(tcpRow));
        Marshal.StructureToPtr(tcpRow, ptr, false);
        
        SetTcpEntry(ptr);
        Marshal.FreeCoTaskMem(ptr);
    }
    
    [StructLayout(LayoutKind.Sequential)]
    private struct MIB_TCPROW
    {
        public uint dwState;
        public uint dwLocalAddr;
        public uint dwLocalPort;
        public uint dwRemoteAddr;
        public uint dwRemotePort;
    }
}

For Firebird database connections, you might want to implement application-level timeouts:

FbConnectionStringBuilder csb = new FbConnectionStringBuilder();
csb.DataSource = "server";
csb.Database = "database.fdb";
csb.UserID = "user";
csb.Password = "password";
csb.Pooling = true;
csb.ConnectionTimeout = 30; // seconds
csb.ConnectionLifeTime = 300; // seconds - maximum connection lifetime

You can enable TCP keepalive at the socket level:

Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
socket.IOControl(IOControlCode.KeepAliveValues, 
    new byte[] { 1, 0, 0, 0, 0x20, 0x4e, 0, 0, 0xd0, 0x07, 0, 0 }, null);

Use PowerShell to monitor TCP connections and their states:

Get-NetTCPConnection -State Established | 
Where-Object {$_.RemotePort -eq 3050} | 
Select-Object LocalAddress, LocalPort, RemoteAddress, RemotePort, State, OwningProcess
  • Implement proper connection disposal in your application
  • Consider using connection pooling where appropriate
  • Monitor connection states regularly
  • Set reasonable timeout values based on your network characteristics