Tech Expert & Vibe Coder

With 14+ years of experience, I specialize in self-hosting, AI automation, and Vibe Coding – building applications using AI-powered tools like Google Antigravity, Dyad, and Cline. From homelabs to enterprise solutions.

Troubleshooting Docker Network MTU Mismatches Causing Intermittent Connection Timeouts in Bridge Networks

Why This Problem Matters to Me

I run multiple Docker containers on Proxmox VMs and a Synology NAS. Most of my services—n8n, Cronicle, monitoring tools, and various automation scripts—live in Docker containers connected to bridge networks. For months, I dealt with random connection timeouts that made no sense. Some containers would fail to reach external APIs intermittently. DNS queries would hang. HTTP requests would time out, then work fine minutes later.

The pattern was maddening because it wasn't consistent. A container might work perfectly for days, then suddenly lose connectivity for a few minutes. Restarting the container would fix it temporarily. I assumed it was a DNS issue at first, then maybe Docker's internal routing. It took me longer than I'd like to admit to realize the actual cause: MTU mismatches.

My Setup and How I Found the Problem

Most of my Docker hosts sit behind a Synology router with a VPN tunnel to my VPS. The VPN uses WireGuard, which adds overhead and reduces the effective MTU from the standard 1500 bytes to around 1420 bytes. My Proxmox VMs run Docker with default settings, meaning containers inherited an MTU of 1500 from the docker0 bridge.

When a container tried to send a packet larger than 1420 bytes through the VPN tunnel, the packet would be dropped or fragmented incorrectly. This caused timeouts, especially with TLS handshakes and large HTTP responses. Small requests worked fine because they stayed under the MTU limit.

I confirmed the issue by running ping tests with the Don't Fragment flag from inside a container:

docker exec -it <container-name> ping -c 4 -s 1472 -M do 8.8.8.8

The ping failed. When I reduced the packet size to 1400 bytes, it worked. That told me the path MTU was lower than Docker's default.

What I Changed and How

I needed to lower the MTU for Docker containers to match the VPN tunnel's limit. I tried three approaches, and only one stuck reliably.

Setting MTU Globally via Docker Daemon

The cleanest fix was editing /etc/docker/daemon.json on each Docker host:

{
  "mtu": 1420
}

Then I restarted Docker:

sudo systemctl restart docker

This applied the MTU to all new containers using the default bridge network. Existing containers kept their old MTU until I recreated them. I had to bring down my stacks with docker-compose down and bring them back up to pick up the new setting.

This worked for most of my setup, but I had one custom bridge network for isolation between certain containers. The global setting didn't apply there.

Creating a Custom Network with Specific MTU

For the isolated network, I created it manually with the MTU set:

docker network create \
  --driver=bridge \
  --opt com.docker.network.driver.mtu=1420 \
  isolated-net

Then I updated my docker-compose.yml to use that network:

networks:
  isolated-net:
    external: true

Containers attached to this network inherited the correct MTU without needing the global daemon setting.

Manual MTU Adjustment (Temporary)

During debugging, I sometimes needed to test MTU changes without recreating containers. I ran a container with elevated permissions:

docker run -it --rm --cap-add=NET_ADMIN alpine /bin/sh

Inside the container, I adjusted the MTU manually:

ip link set dev eth0 mtu 1420

This only lasted until the container stopped. It was useful for testing but not a real solution.

What Worked and Why

Setting the MTU globally through the Docker daemon fixed the intermittent timeouts. Containers stopped trying to send oversized packets through the VPN tunnel. DNS queries and HTTP requests became stable.

The custom network approach worked well for containers that needed different MTU settings. I didn't need it often, but having the option kept my setup flexible without forcing everything to the same value.

Verifying the MTU after making changes was critical. I checked it on each container's interface:

docker exec <container-name> ip link show eth0

The output showed the MTU value in use. If it didn't match what I configured, I knew something was wrong with the network setup or the container needed to be recreated.

What Didn't Work

I initially tried adjusting the MTU on the host's physical interface, thinking Docker would inherit it automatically. It didn't. Docker sets its own MTU for bridge networks, and the host's interface setting had no effect.

I also assumed restarting containers would apply the new MTU from the daemon config. It didn't. Containers kept the MTU they were created with. I had to recreate them, which meant downtime for some services.

Using manual MTU adjustments inside containers seemed like a quick fix, but it didn't persist. Every time a container restarted, the MTU reset to the default. I wasted time chasing this before realizing it was temporary.

Key Takeaways

MTU mismatches cause subtle, hard-to-diagnose connectivity issues. They don't break everything—just enough to make things unreliable. If you see random timeouts, especially over VPNs or tunnels, check the MTU first.

Docker's default MTU is 1500 bytes. If your network path supports less, you need to configure Docker explicitly. The daemon config is the most reliable way to do this for the default bridge network. Custom networks need their MTU set during creation.

Always verify the MTU after making changes. Don't assume it applied correctly. Check the container's interface with ip link show and test connectivity with ping or actual traffic.

Recreating containers is necessary when changing MTU settings. Restarting them isn't enough. Plan for downtime or use rolling updates if you're running production services.

MTU issues are more common than I expected. VPNs, cloud overlays, and tunneling protocols all reduce the effective MTU. If you run Docker in any of these environments, set the MTU explicitly to avoid problems later.