Skip to content

[Windows/WSL2] com.docker.backend keeps host TCP sockets in "Bound" state after container connections close, never released (reproduces on 4.96.0) #769

Open

Description

@gregeldridge

Bug report

Bug description

On Windows with the WSL2 backend, com.docker.backend keeps piling up TCP sockets in the Bound state on the Windows host: 0.0.0.0:<ephemeral port>, no remote endpoint, all owned by one com.docker.backend process. Each comes from a container connection that has already finished. They aren't released until Docker Desktop restarts. Each one permanently takes a port from Windows' ephemeral range (49152–65535), which every process on the host shares.

Expected: after a container's connection closes, com.docker.backend releases its host-side socket.
Actual: some connections leave a Bound socket behind for days, until Docker Desktop restarts.

On an earlier version (4.81.0) with heavier traffic, the same backend reached ~14,300 held sockets after 15 days, leaving ~1,400 free ephemeral ports. That caused host-wide intermittent connection failures: DNS timeouts and TLS "unexpected EOF" in containers, plus connect timeouts from native Windows processes. ICMP to the gateway kept working. Restarting Docker Desktop released everything at once.

Evidence on 4.96.0

Docker Desktop was updated to 4.96.0 (backend restarted with a clean count). After 47.4 hours:

Measure Value
com.docker.backend sockets in Bound 120
Released over the period 1 of 121
Age of the held sockets 22 older than 36 h, 32 aged 24–36 h, 28 aged 12–24 h, 36 aged 1–12 h, 2 under 1 h
Leak rate ~60 per day

The leaks happen in bursts that line up, to the second, with scheduled jobs in two unrelated containerized apps:

Source Sockets held per run
App 1 (qbit_manage, 4 instances, one round every 4 h) 6 per 4-hour cycle, on all 11 cycles over 47 h (4 at the main round + 2 at one instance whose schedule shifted)
App 2 (Kometa, one run daily) 9 and 14 on the two daily runs

Background is ~0: with neither job running for 20 minutes, the Bound total stayed flat (605 → 605, measured on 4.81). Over the same 20 minutes com.docker.backend carried 417 other connections without leaking: BitTorrent peers, HTTPS to the internet, and HTTP to services on the host.

Which connections leak

I triggered each App 1 instance on its own (on 4.81; the per-run counts are the same on 4.96) and recorded what each leaked socket had been connected to:

Instance Held sockets per run Leaked socket's prior connection
A 1 an external HTTPS API on :443, Cloudflare-fronted (matched to the app's notification service by DNS and by timing)
B 1 (same app flow)
C 2 the same external API, plus 127.0.0.1:8088, which is how the backend reaches a native Windows HTTP service the container calls at host.docker.internal:8088
D 2 (same configuration as C)

Most connections from the same containers don't leak, including other connections to the same API's other addresses. In one test, a single unauthenticated request from a container to the native service at host.docker.internal:8088 left the backend's host-side socket in CLOSE_WAIT for ~2 minutes. It was then still held as Bound 13+ minutes later, when the check ended.

Reproduction steps

  1. Run a containerized client that periodically calls (a) an external HTTPS API and (b) a native Windows HTTP service through host.docker.internal:<port>. I saw this with a Python requests / qbittorrent-api client.
  2. On the Windows host, record the held sockets before and after each client run:
    $ids = (Get-Process com.docker.backend).Id
    (Get-NetTCPConnection -State Bound | Where-Object { $_.OwningProcess -in $ids }).Count
    # age profile: anything hours old is a leak; momentary or minutes-long Bound states are normal
    Get-NetTCPConnection -State Bound | Where-Object { $_.OwningProcess -in $ids } |
      Group-Object { $_.CreationTime.ToString('MM-dd HH') }
  3. Each run leaves 1–2 sockets per client session that stay Bound for days.

Minimal standalone repro: not yet found. One-shot curl, Python urllib and requests calls from a container to the same external endpoint didn't leak. A throwaway nginx target produced Bound sockets that were all released within ~5–9 minutes. Only count sockets that stay Bound for hours.

Environment notes

Impact

Exhaustion is slow at this host's current traffic (~60 sockets a day). Before I identified the trigger and moved the busiest client off the host.docker.internal path, though, the leak used up nearly the whole ephemeral range in about two weeks and broke outbound connectivity for every process on the host. Restarting Docker Desktop is the only remedy.

Platform

Windows

Version information

Client:
 Version:           29.9.1
 API version:       1.56
 Go version:        go1.26.9
 Git commit:        dfc520d
 Built:             Wed Oct 14 18:34:24 2026
 OS/Arch:           windows/amd64
 Context:           desktop-linux

Server: Docker Desktop 4.96.0 (243774)
 Engine:
  Version:          29.9.1
  API version:      1.56 (minimum version 1.40)
  Go version:       go1.26.9
  Git commit:       b26fb77
  Built:            Wed Oct 14 18:32:24 2026
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v2.4.2
  GitCommit:        b7a25261e029d68978bbf290df0a62fc819b3c51
 runc:
  Version:          1.5.2
  GitCommit:        v1.5.2-0-g29dd3dc2
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

Client:
 Version:    29.9.1
 Context:    desktop-linux
 Debug Mode: false
 Plugins:
  agent: Docker AI Agent Runner (Docker Inc.)
    Version:  v1.149.0
    Path:     C:\Program Files\Docker\cli-plugins\docker-agent.exe
  ai: Docker AI Agent - Ask Gordon (Docker Inc.)
    Version:  v1.31.0
    Path:     C:\Program Files\Docker\cli-plugins\docker-ai.exe
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.38.0
    Path:     C:\Program Files\Docker\cli-plugins\docker-buildx.exe
  compose: Docker Compose (Docker Inc.)
    Version:  v5.6.0
    Path:     C:\Program Files\Docker\cli-plugins\docker-compose.exe
  debug: Get a shell into any image or container (Docker Inc.)
    Version:  0.0.47
    Path:     C:\Program Files\Docker\cli-plugins\docker-debug.exe
  desktop: Docker Desktop commands (Docker Inc.)
    Version:  4.96.0
    Path:     C:\Program Files\Docker\cli-plugins\docker-desktop.exe
  dhi: CLI for managing Docker Hardened Images (Docker Inc.)
    Version:  v0.0.7
    Path:     C:\Program Files\Docker\cli-plugins\docker-dhi.exe
  extension: Manages Docker extensions (Docker Inc.)
    Version:  v0.2.31
    Path:     C:\Program Files\Docker\cli-plugins\docker-extension.exe
  init: Creates Docker-related starter files for your project (Docker Inc.)
    Version:  v1.4.0
    Path:     C:\Program Files\Docker\cli-plugins\docker-init.exe
  mcp: Docker MCP Plugin (Docker Inc.)
    Version:  v0.44.1
    Path:     C:\Program Files\Docker\cli-plugins\docker-mcp.exe
  model: Docker Model Runner (Docker Inc.)
    Version:  v1.2.6
    Path:     C:\Program Files\Docker\cli-plugins\docker-model.exe
  offload: Docker Offload (Docker Inc.)
    Version:  v0.7.4
    Path:     C:\Program Files\Docker\cli-plugins\docker-offload.exe
  pass: Docker Pass Secrets Manager Plugin (beta) (Docker Inc.)
    Version:  v0.3.0
    Path:     C:\Program Files\Docker\cli-plugins\docker-pass.exe
  sandbox: "docker sandbox" is deprecated, use Docker Sandboxes instead (Docker Inc.)
    Version:  v0.13.0
    Path:     C:\Program Files\Docker\cli-plugins\docker-sandbox.exe
  scout: Docker Scout (Docker Inc.)
    Version:  v1.26.0
    Path:     C:\Program Files\Docker\cli-plugins\docker-scout.exe

Server:
 Containers: 18
  Running: 16
  Paused: 0
  Stopped: 2
 Images: 27
 Server Version: 29.9.1
 Storage Driver: overlayfs
  driver-type: io.containerd.snapshotter.v1
 Logging Driver: local
 Cgroup Driver: cgroupfs
 Cgroup Version: 2
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
 CDI spec directories:
  /etc/cdi
  /var/run/cdi
 Discovered Devices:
  cdi: docker.com/gpu=webgpu
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 nvidia runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: b7a25261e029d68978bbf290df0a62fc819b3c51
 runc version: v1.5.2-0-g29dd3dc2
 init version: de40ad0
 Security Options:
  seccomp
   Profile: builtin
  cgroupns
 Kernel Version: 6.6.87.1-microsoft-standard-WSL2
 Operating System: Docker Desktop
 OSType: linux
 Architecture: x86_64
 CPUs: 8
 Total Memory: 15.59GiB
 Name: docker-desktop
 ID: <redacted>
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 HTTP Proxy: http.docker.internal:3128
 HTTPS Proxy: http.docker.internal:3128
 No Proxy: hubproxy.docker.internal
 Labels:
  com.docker.desktop.address=npipe://\\.\pipe\docker_cli
 Experimental: false
 Insecure Registries:
  hubproxy.docker.internal:5555
  127.0.0.0/8
  ::1/128
 Live Restore Enabled: false
 Firewall Backend: iptables

Diagnostics ID

C8E50518-8ACE-49CD-B98F-A902B3569482/20261021152506

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions