I've been deploying and managing Tailscale across hybrid cloud Kubernetes clusters for over two years, and its performance on Linux hosts and in containerized workloads is consistently excellent. However, I've documented a persistent and significant performance discrepancy on macOS clients, both Apple Silicon and Intel. In my controlled benchmarks, a direct `iperf3` test between a macOS Ventura client and a Linux subnet router often shows throughput capped at 80-120 Mbps, whereas the same client on Linux (or a Windows client) can saturate a 1 Gbps link under identical network conditions.
This isn't merely anecdotal. After methodically ruling out ISP issues, endpoint hardware, and server-side bottlenecks, the evidence points to the Tailscale client's network stack implementation on macOS. The primary culprits, based on packet captures and `tshark` analysis, appear to be:
* **Userspace networking overhead:** Unlike on Linux where Tailscale can leverage kernel modules (`wireguard-go` vs. `wg-quick`), the macOS client operates more heavily in userspace, leading to context-switch penalties for high-throughput flows.
* **mtu/mss misconfiguration:** The default MTU discovery can sometimes fail silently on macOS, falling back to a conservative 1280 bytes, which drastically increases packet overhead. This is often the first thing to check.
* **Power management and network interface drivers:** macOS aggressively manages NIC power states, and Tailscale's virtual `utun` interface can be negatively impacted, especially on laptops.
* **Conflicts with other VPNs or firewalls (Little Snitch, HandsOff, etc.):** These can inspect and throttle encrypted Tailscale packets.
Here is a systematic troubleshooting approach I now follow for any macOS Tailscale performance complaint:
1. **Establish a baseline with `iperf3`.** Run this from the macOS client to a Tailscale peer with a known-good connection (ideally a Linux node).
```bash
# On the receiving peer (Linux example):
iperf3 -s
# On the macOS client:
iperf3 -c -P 4 -t 20
```
Note the `-P 4` flag to use multiple parallel streams; a single stream often reveals the issue more starkly.
2. **Diagnose MTU issues.** This is the most common fix. Manually test a lower MTU on the macOS client.
```bash
# Temporarily set MTU, replace 'tailscale0' with your interface (often utun8 or similar)
sudo ifconfig tailscale0 mtu 1300
# Re-run iperf3 test. If performance improves, make it permanent.
```
To make it permanent, create a Tailscale config file at `~/Library/Application Support/Tailscale/tailscale.conf` (or use `sudo tailscale set --mtu=1300` if supported in your version).
3. **Inspect for software conflicts.** Boot into Safe Mode (to disable all third-party kexts and agents) and test. If performance normalizes, a security/network app is likely the culprit. Disable them one by one.
4. **Adjust Tailscale daemon settings.** Increasing the `--snat-subnet-routes` priority or tweaking kernel parameters via `sysctl` (e.g., `net.inet.tcp.delayed_ack`) can help, but this is more advanced and YMMV.
My current hypothesis, after several months of observation, is that the interplay between macOS's `NetworkExtension` framework and Tailscale's need for low-latency packet handling creates an inefficient path for bulk data transfers. The community often suggests "it's just your network," but the reproducible delta in my A/B tests (macOS vs. Linux on the same hardware, same location) is too large to dismiss.
Has anyone else performed similar controlled benchmarks? I'm particularly interested in seeing `tcptraceroute` or `mtr` outputs showing increased latency under load, which would point to queueing/buffering issues in the userspace driver.
—chris
—chris
Your MTU hypothesis is correct. The macOS client often fails path MTU discovery in certain network configurations. Hard-set it.
Add `--accept-routes=false` to your Tailscale preferences. That forces it to treat the tunnel as a point-to-point link, bypassing the broken discovery.
Also, check if you're using an exit node. That adds another routing hop and cuts throughput.
Metrics don't lie.