How-To

Docker Networking Troubleshooting: Fix Container Connection Failures on Linux (2026)

17 min read

Docker networking failures are irritating in a specific way: the error message is never the actual problem. “Connection refused” could mean a dozen different things. Your containers are running, ports are published, and nothing works. This guide goes symptom by symptom through the most common Docker networking failures on Linux, with a Windows Server section at the end.

Tested on Ubuntu 24.04 with Docker Engine 27.x.

Table of Contents

Quick Diagnosis: Start Here

Before diving into a specific issue, run these four commands. They give you a complete picture of your network state in under two minutes.

1. List all Docker networks:

docker network ls
Terminal output of 'docker network ls' showing NETWORK ID, NAME, DRIVER, SCOPE columns with bridge, host, none, and at least one user-defined network visible

2. Check which network your container is actually on:

docker inspect <container_name> --format '{{json .NetworkSettings.Networks}}' 

3. Inspect the network in question, this shows attached containers and their IPs:

docker network inspect <network_name>
Terminal output of 'docker network inspect' showing Subnet, Gateway under IPAM Config, and a Containers section with container names and IPv4Addresses

4. Check if the container is actually running and what ports are published:

docker ps
Terminal output of 'docker ps' showing CONTAINER ID, IMAGE, STATUS, and PORTS column with 0.0.0.0:8080->80/tcp style mappings visible

If those four commands don’t immediately reveal the problem, find your specific symptom below.

Symptoms and Likely Causes

SymptomLikely CauseJump To
Connection refused between containersDifferent networks, or default bridge (no DNS)Issue 1
Published port unreachable from host or LANPort conflict, wrong interface binding, iptablesIssue 2
Name or service not known inside containerDocker DNS not working, bad resolv.confIssue 3
address already in use on container startAnother process owns that host portIssue 4
All container networking suddenly brokeniptables chains wiped by flush or firewall toolIssue 5
Container can’t ping or reach the hostHost firewall blocking Docker subnetIssue 6
Connections hang or partially work, no errorsMTU mismatch on VPN or cloud networkIssue 7

Issue 1: Containers Can’t Talk to Each Other

Symptoms:

  • curl: (7) Failed to connect when one container tries to reach another by name
  • ping: unknown host <container_name> from inside a container
  • App logs show database connection refused even though both containers are running

Cause: The most common reason is that both containers are on the default bridge network. The default bridge does not provide DNS. Containers can only reach each other by IP, and those IPs change on restart. The fix is a user-defined network, which gives you automatic DNS resolution by container name.

A secondary cause is that the containers are on different networks entirely.

Diagnosis:

# Check which network container A is on
docker inspect app_container --format '{{json .NetworkSettings.Networks}}'

# Check which network container B is on
docker inspect db_container --format '{{json .NetworkSettings.Networks}}'

If the network names don’t match, that’s your problem.

Fix: create a user-defined network and attach both containers:

# Create a named network
docker network create myapp-net

# If containers are already running, connect them to the new network
docker network connect myapp-net app_container
docker network connect myapp-net db_container

# Verify both containers appear in the network
docker network inspect myapp-net

For new deployments, pass --network at run time:

docker run -d --name db --network myapp-net postgres:16
docker run -d --name app --network myapp-net my-app-image

Now app can reach db at the hostname db no IP addresses needed.

Verify:

# Ping by container name from inside the app container
docker exec -it app_container ping db_container

# Or test the actual service port
docker exec -it app_container curl http://db_container:5432

Why user-defined networks? On the default bridge, Docker doesn’t run a DNS resolver. On any user-defined network, Docker injects an internal DNS server at 127.0.0.11 that resolves container names automatically. This is also why Docker Compose works out of the box. Compose always creates a user-defined network for each project.

Issue 2: Published Port Not Reachable

Symptoms:

  • curl: (7) Failed to connect to localhost port 8080 from the host
  • Port shows in docker ps but times out from another machine
  • Browser shows “This site can’t be reached”

Cause: Three things commonly cause this: (1) another process already owns the host port, (2) Docker bound to 127.0.0.1 instead of 0.0.0.0 so the port is only reachable locally, or (3) iptables rules are blocking the traffic.

Diagnosis:

# Step 1: Confirm the port mapping in docker ps
docker ps --format "table {{.Names}}\t{{.Ports}}"

Look at the PORTS column. 0.0.0.0:8080->80/tcp means it’s reachable from anywhere. 127.0.0.1:8080->80/tcp means localhost only. That distinction matters.

# Step 2: Test the port locally on the host
curl http://127.0.0.1:8080

# Step 3: Test from another machine (replace 192.168.1.100 with your host IP)
# Install nmap if needed: sudo apt install nmap
nmap -p 8080 192.168.1.100
# Step 4: Check Docker's iptables rules for the DOCKER chain
sudo iptables -L DOCKER -n -v
Terminal output of 'sudo iptables -L DOCKER -n -v' showing Docker-managed firewall rules for container port forwarding

Fix, if Docker bound to 127.0.0.1 only:

Stop and re-run the container with an explicit 0.0.0.0 binding:

docker run -d -p 0.0.0.0:8080:80 my-image

Or set this globally in /etc/docker/daemon.json so all published ports bind to all interfaces by default. Only do this if your host firewall controls external access:

{
  "ip": "0.0.0.0"
}

Then sudo systemctl restart docker.

Fix, if iptables is blocking traffic:

Rather than disabling your firewall, add a targeted rule to the DOCKER-USER chain. Docker reads this chain before its own rules. It’s the safe place for custom firewall logic:

# Allow traffic from your LAN to the container port
sudo iptables -I DOCKER-USER -p tcp --dport 8080 -s 192.168.1.0/24 -j ACCEPT

Verify:

curl http://127.0.0.1:8080
# Expected: HTTP response from your container, not a connection error

Issue 3: DNS Fails Inside a Container

Symptoms:

  • curl: (6) Could not resolve host: google.com from inside a container
  • nslookup: can't resolve inside a container
  • App can’t reach external APIs by hostname, but can reach them by IP

Cause: Docker injects 127.0.0.11 as the DNS resolver inside containers on user-defined networks. If that resolver can’t forward queries upstream, because the host’s systemd-resolved is conflicting, because /etc/resolv.conf inside the container is empty, or because iptables is blocking UDP port 53, name resolution fails entirely.

Diagnosis:

# Step 1: Check what DNS server the container is configured to use
docker exec -it <container_name> cat /etc/resolv.conf
Terminal output of 'docker exec -it container cat /etc/resolv.conf' showing nameserver 127.0.0.11 — Docker's internal DNS resolver address

You should see nameserver 127.0.0.11. If you see nameserver 127.0.0.53 or nothing useful, Docker is inheriting a broken resolver from the host.

# Step 2: Test DNS resolution from inside the container
docker exec -it <container_name> nslookup google.com

# Step 3: Check if the host's systemd-resolved is running and what port it's on
sudo ss -ulnp | grep 53
# Step 4: Check iptables isn't blocking Docker's DNS proxy on port 53
sudo iptables -L DOCKER -n | grep 53

Fix, override DNS for a single container:

docker run --dns 1.1.1.1 --dns 8.8.8.8 my-image

Fix, override DNS globally for all containers (edit /etc/docker/daemon.json):

{
  "dns": ["1.1.1.1", "8.8.8.8"]
}
sudo systemctl restart docker

Fix, if systemd-resolved is conflicting on Ubuntu:

Ubuntu 22.04+ runs systemd-resolved, which binds to 127.0.0.53. This can interfere with Docker’s DNS proxy. Point Docker at the real upstream resolver instead:

# Find your actual upstream DNS server
resolvectl status | grep "DNS Servers"

# Then add that IP to daemon.json instead of 127.0.0.53

Verify:

docker exec -it <container_name> nslookup google.com
# Expected output: Server: 127.0.0.11 (or your override), followed by a resolved address

Issue 4: Port Binding Conflict

Symptoms:

  • docker: Error response from daemon: driver failed programming external connectivity: Bind for 0.0.0.0:80 failed: port is already allocated
  • Container fails to start, exits immediately with a port error

Cause: Something else on the host, whether another container, nginx, Apache, or any other service, is already listening on the host port you’re trying to publish. Docker can’t bind to a port that’s already taken.

Diagnosis:

# Find what's using port 80 (replace 80 with your port)
sudo ss -tlnp | grep :80
Terminal output of 'sudo ss -tlnp | grep 80' showing a process already bound to port 80 with its PID and process name visible in the output

The output shows the listening address, port, and the process name with PID in brackets. For example: users:(("nginx",pid=1234,fd=6)).

# Alternative using lsof (install if needed: sudo apt install lsof)
sudo lsof -i :80

# If it's another Docker container
docker ps | grep "0.0.0.0:80"

Fix, stop the conflicting process:

# If it's a system service
sudo systemctl stop nginx

# If it's another Docker container
docker stop <container_id>

Fix, use a different host port instead:

If you can’t stop the conflicting service, map Docker to a different host port:

# Map host port 8080 to container port 80
docker run -d -p 8080:80 my-image

In a Docker Compose file:

ports:
  - "8080:80"

Verify:

docker ps
# Confirm the container is now running with the new port mapping in the PORTS column
curl http://localhost:8080

Issue 5: Docker Networking Breaks After iptables Flush

Symptoms:

  • All container networking suddenly stops working
  • Containers can’t reach the internet or each other
  • Problem started right after running iptables -F, enabling ufw, or running a security hardening script

Cause: Docker manages a set of iptables chains, DOCKER, DOCKER-USER, DOCKER-ISOLATION-STAGE-1, and DOCKER-ISOLATION-STAGE-2 that it creates when the daemon starts. These chains route traffic to and from containers. When you run iptables -F or a tool like ufw resets the firewall, Docker’s chains get wiped. Container traffic has nowhere to go.

Think of iptables chains as a sorted list of traffic rules. Docker adds its own rules to route packets into containers. Flush the list, and Docker’s routing disappears.

Diagnosis:

# Check if Docker's chains are present — if this returns nothing, they're gone
sudo iptables -L | grep DOCKER

No output means Docker’s firewall rules have been wiped.

Fix, restart the Docker daemon to regenerate all rules:

sudo systemctl restart docker

Containers keep running through a daemon restart on Linux; their processes aren’t killed. But verify:

docker ps
# Confirm containers are still in "Up" state

Fix, if you’re using ufw, configure it to work with Docker instead of against it:

Don’t disable ufw. Instead, allow Docker’s bridge subnet through the FORWARD chain:

# Edit /etc/default/ufw
sudo nano /etc/default/ufw
# Change: DEFAULT_FORWARD_POLICY="DROP"
# To:     DEFAULT_FORWARD_POLICY="ACCEPT"

sudo ufw reload
sudo systemctl restart docker

Verify:

# Confirm Docker's chains are back
sudo iptables -L DOCKER -n -v

# Test container connectivity
docker exec -it <container_name> curl http://google.com

Rule of thumb: Never run iptables -F on a Docker host without immediately restarting the Docker daemon. Better yet, use the DOCKER-USER chain for your custom rules. Docker never touches that chain’s contents, so your rules survive a daemon restart.

Issue 6: Containers Can’t Reach the Host Machine

Symptoms:

  • A container can reach the internet but can’t connect to a service on the host (like a local database)
  • ping 172.17.0.1 from inside a container fails
  • App inside a container can’t connect to localhost because inside a container, localhost means the container itself, not the host

Diagnosis:

# Find the Docker bridge IP — this is the host's address as seen from containers
ip addr show docker0
Terminal output of 'ip addr show docker0' showing inet 172.17.0.1/16 — the host's IP address as seen from containers on the default bridge network

The inet line shows the host’s Docker bridge IP, typically 172.17.0.1. Containers on the default bridge can reach the host at this address.

# Test from inside the container
docker exec -it <container_name> ping 172.17.0.1

If ping fails, the host firewall is likely blocking the Docker subnet.

Fix, allow the Docker bridge subnet to reach the host:

# Add a targeted INPUT rule for the docker0 interface
sudo iptables -I INPUT -i docker0 -j ACCEPT

For user-defined networks, the bridge interface has a generated name. Find it:

docker network inspect myapp-net --format '{{.Options}}'
# Look for com.docker.network.bridge.name, or use:
ip link show | grep br-

Then apply the same rule with that interface name.

Fix, use host-gateway for a portable solution (Docker 20.10+):

Instead of hardcoding the bridge IP, use Docker’s built-in host-gateway target. It always resolves to the correct host IP regardless of which bridge network you’re on:

docker run --add-host=host.docker.internal:host-gateway my-image

In Docker Compose:

extra_hosts:
  - "host.docker.internal:host-gateway"

Verify:

docker exec -it <container_name> ping host.docker.internal
# Should resolve and respond from the host

Issue 7: Silent Failures: MTU Mismatch

Symptoms:

  • Connections appear to work but hang partway through, especially for large responses
  • Small requests succeed (like a health check ping) but large file transfers or API responses never complete
  • Problem only appears inside Docker, not on the host directly
  • Common in AWS, GCP, or VPN-connected environments

Cause: Docker’s default MTU is 1500 bytes. MTU is the largest packet size the network can carry. In VPN tunnels or cloud environments, the real MTU is often lower: 1450 in many VPN setups, 1480 in some cloud environments. Large packets get silently dropped. Small packets get through fine. That’s why the problem looks intermittent, even though it isn’t.

Diagnosis:

# Check the host's primary interface MTU
ip link show eth0
# Look for 'mtu XXXX' in the output — if it's less than 1500, you may have a mismatch

# Use tcpdump to watch for retransmissions on the Docker bridge
sudo tcpdump -i docker0 -n
Terminal output of 'sudo tcpdump -i docker0 -n' showing packet capture on the Docker bridge interface with container IP addresses in the 172.17.x.x range visible in source and destination fields

While tcpdump is running, reproduce the failing connection from another terminal. Repeated retransmissions of the same sequence numbers point to packet loss, not a flaky service.

# Check the current MTU on Docker's bridge network
docker network inspect bridge --format '{{json .Options}}'

Fix, set Docker’s MTU to match or be slightly below the host’s effective MTU:

Edit /etc/docker/daemon.json:

{
  "mtu": 1450
}
sudo systemctl restart docker

# Recreate any custom networks to pick up the new MTU
docker network rm myapp-net
docker network create myapp-net

Verify:

docker network inspect bridge --format '{{json .Options}}'
# Should show: {"com.docker.network.driver.mtu":"1450"}

Test the previously failing large transfer, it should now complete successfully.

Windows Server: HNS and the nat Network Driver

Docker networking on Windows Server works differently at every layer. Instead of iptables and Linux bridges, Windows uses the Host Networking Service (HNS), a Windows component that manages virtual switches and network endpoints for containers. The default network driver is nat (not bridge), and the bridge driver doesn’t exist on Windows.

Common Windows-specific symptoms:

  • Containers fail to start with HNS-related errors after a Windows update or unexpected reboot
  • docker network ls shows the nat network but containers can’t reach the internet
  • Network endpoints get stuck in a bad state after Docker restarts

Diagnosis in PowerShell:

# Check Docker service status
Get-Service docker

# List Docker networks
docker network ls

# Inspect the default nat network
docker network inspect nat

# View recent Docker events for networking errors
docker events --since 1h

Fix, reset HNS state (the standard fix for corrupted Windows container networking):

Warning: This drops all container network connections. Stop your containers first.

# Stop all running containers
docker stop $(docker ps -q)

# Stop Docker and the HNS service
Stop-Service docker
Stop-Service hns

# Clear HNS policy state
Remove-Item -Recurse -Force "C:\ProgramData\Microsoft\Windows\HNS\Policy"

# Restart both services
Start-Service hns
Start-Service docker

Verify on Windows:

# Test internet connectivity from a Windows container
docker run --rm mcr.microsoft.com/windows/nanoserver:ltsc2022 cmd /c ping google.com

Key differences to remember:

AspectLinux DockerWindows Server Docker
Default network driverbridgenat
Firewall managementiptablesHNS / Windows Firewall
DNS resolver in containers127.0.0.11Windows DNS client
Host networking mode--network host (full)--network host (limited support)
Bridge driverAvailableNot available
Diagnostic tooliptables, tcpdumpGet-HNSNetwork, Event Viewer

For a full walkthrough of Docker on Windows Server setup, see the official Windows container networking architecture docs.

Error Messages Quick Reference

Error MessageCauseFix
port is already allocatedHost port taken by another processFind with ss -tlnp, stop process or change host port
address already in useSame as aboveSame as above
Name or service not knownDNS resolution failure inside containerCheck resolv.conf, override DNS with --dns flag
No such container: <name>Container not running or wrong nameRun docker ps -a to see all containers including stopped
network <name> not foundNetwork was removed or never createdRun docker network create <name>
Failed to create endpointHNS error (Windows) or iptables issueRestart Docker daemon; on Windows, reset HNS
connection refusedService not listening, wrong port, or wrong networkCheck container is on same network; verify app binds to 0.0.0.0 not 127.0.0.1
i/o timeoutFirewall blocking, MTU mismatch, or wrong IPCheck iptables DOCKER-USER chain; test MTU
driver failed programming external connectivityiptables rules missing after flushRestart Docker daemon

Configuration Mistakes to Avoid

Mistake 1: Relying on container IPs instead of names

Container IPs change every restart. Don’t hardcode them.

# Wrong — this IP will change
docker run --env DB_HOST=172.17.0.3 my-app

# Right — use container names on a user-defined network
docker run --network myapp-net --env DB_HOST=db my-app

Mistake 2: App listening on 127.0.0.1 inside the container

If your app binds to 127.0.0.1 inside the container, Docker can publish the port but nothing from outside, including other containers, can reach it. This accounts for a surprising number of “Docker networking is broken” reports.

# Check what address your app is listening on inside the container
docker exec -it <container_name> ss -tlnp
# Look for 127.0.0.1:<port> vs 0.0.0.0:<port>
# The app itself needs to bind to 0.0.0.0 — this is an app config issue, not a Docker issue

Mistake 3: Setting "iptables": false in daemon.json without managing rules yourself

This disables Docker’s automatic firewall management. If you set it, you are responsible for all routing rules. Most users should leave this at the default true.

Mistake 4: Using --network host without understanding the implications

--network host removes container network isolation. The container shares the host’s network stack directly. It solves connectivity problems but bypasses Docker’s port publishing and exposes all container ports on the host. Use it deliberately, not as a debugging shortcut.

Correct daemon.json for a typical setup with DNS override and MTU adjustment:

{
  "dns": ["1.1.1.1", "8.8.8.8"],
  "mtu": 1450,
  "log-driver": "journald"
}

After any change to daemon.json:

sudo systemctl restart docker

Getting Help: Logs and Debug Info

When you need to dig deeper or report a problem, here’s where to look:

Container logs:

docker logs <container_name>
docker logs --tail 50 --follow <container_name>

Docker daemon logs (systemd):

sudo journalctl -u docker.service --since "1 hour ago"

Full container network configuration:

docker inspect <container_name>

All iptables rules Docker has created:

sudo iptables -L -n -v
sudo iptables -t nat -L -n -v

Live packet capture on the Docker bridge:

# Capture all traffic on docker0 (install tcpdump: sudo apt install tcpdump)
sudo tcpdump -i docker0 -n

# Filter to a specific port
sudo tcpdump -i docker0 -n port 80

# Save to file for later analysis
sudo tcpdump -i docker0 -n -w /tmp/docker-capture.pcap

Community and official resources:

Prevention Tips

  • Always use user-defined networks. Never rely on the default bridge for multi-container apps. Create a named network in your Compose file or run command from day one.
  • Pin your port bindings explicitly. Use 0.0.0.0:<port>:<port> or 127.0.0.1:<port>:<port> intentionally. Don’t let Docker decide which interface to bind to.
  • Set MTU in daemon.json proactively on cloud and VPN hosts. If you’re on AWS, GCP, Azure, or any VPN-connected server, set "mtu": 1450 before you see problems.
  • Use the DOCKER-USER chain for custom firewall rules. Rules you add here survive Docker daemon restarts. Rules you add to the DOCKER chain get overwritten.
  • Keep a daemon.json in version control. A documented /etc/docker/daemon.json means you can reproduce your network configuration on a new host in under a minute.
  • Don’t run iptables -F on a Docker host. If you must reset iptables, immediately follow with sudo systemctl restart docker.
  • Check app bind addresses, not just Docker config. Half of “Docker networking is broken” reports turn out to be an app listening on 127.0.0.1 inside the container. Verify with docker exec -it <container> ss -tlnp.

Wrapping Up

Most Docker networking failures come down to three root causes: containers on the wrong network, iptables rules getting wiped, or an app binding to the wrong address. The diagnostic workflow is the same every time. docker network ls, docker network inspect, ss -tlnp, and tcpdump when packets disappear silently.

Make docker network inspect your first move when a container connection fails. It shows which containers are on which network and what IPs they have. That alone eliminates half the possible causes before you’ve changed anything.

Last updated: June 2026 | Applies to Docker Engine 27.x on Ubuntu 24.04 / Debian 12, with Windows Server 2019/2022 callout