Get Moshi
Back to Articles

Fix Mosh Falling Back to SSH on macOS

Why Homebrew's default PATH setup breaks Mosh on macOS, how shell config files work for zsh, bash, and fish, and the one-line fix for each

Fix Mosh Falling Back to SSH on macOS

Fix Mosh Falling Back to SSH on macOS

You configured Mosh, your connection "works" — but you're actually on plain SSH. Here's why Homebrew's default setup breaks Mosh, and how to fix it for zsh, bash, and fish.


TL;DR: Mosh bootstraps by running mosh-server new through a non-interactive SSH shell. On macOS, Homebrew's installer tells you to add its PATH to ~/.zprofile — a file that only loads for login shells. Non-interactive shells never see it, so mosh-server isn't found and your client silently falls back to SSH. The fix: move your Homebrew PATH setup to ~/.zshenv (zsh) or ~/.bashrc (bash). One line, and Mosh, the Moshi tmux session picker, and every other Homebrew tool start working over SSH.


The Symptoms

When Homebrew's PATH is missing from non-interactive shells, multiple things break at once:

  • The tmux session picker doesn't appear on connect — Moshi detects sessions by running tmux ls over SSH before opening your terminal. If tmux (a Homebrew binary) isn't in the non-interactive PATH, the detection fails silently and you go straight to a bare shell
  • Mosh falls back to SSH — if your connection mode is "Auto", Moshi tries Mosh first, but mosh-server (also Homebrew) isn't found, so it silently falls back to plain SSH. You lose reconnection after network switches, roaming when the app suspends, and UDP-based latency reduction. You can check which protocol you're on by looking at the badge in the top-right corner of the terminal — it reads "Mosh" or "SSH"
  • Remote commands can't find tools — any ssh user@mac 'some-homebrew-command' fails with "command not found"

All three symptoms share the same root cause, and the same one-line fix resolves all of them.


Why Homebrew's Default Setup Breaks Mosh

Mosh connects in two steps:

  1. The client runs ssh user@host -- 'mosh-server new' to start a server process
  2. It reads the port and key from the response and switches to a direct UDP connection

Step 1 runs through a non-interactive, non-login shell. It's SSH executing a command, not opening a terminal session. And that distinction matters because of how shells load their config files.

What Homebrew tells you to do

After installing Homebrew on Apple Silicon, the installer prints:

==> Next steps:
- Run this command in your terminal to add Homebrew to your PATH:
    eval "$(/opt/homebrew/bin/brew shellenv)"
- Add it to your shell profile:
    echo >> ~/.zprofile
    echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile

Homebrew recommends ~/.zprofile. This is a login shell config file — it loads when you open Terminal.app, iTerm2, or start a new login session. For everyday use, it works fine.

But when Mosh bootstraps through SSH, the shell that executes mosh-server new is non-interactive and non-login. It never reads ~/.zprofile. The PATH stays at the system default — /usr/bin:/bin:/usr/sbin:/sbin — and mosh-server isn't found.

Why Homebrew chose .zprofile over .zshenv

There's a reason Homebrew doesn't recommend ~/.zshenv, even though it would solve this problem. macOS ships with /etc/zprofile, which runs /usr/libexec/path_helper — a system utility that reorders your PATH by reading /etc/paths and /etc/paths.d/*. Since /etc/zprofile runs after ~/.zshenv but before ~/.zprofile, any PATH you set in ~/.zshenv gets rearranged: system paths move to the front, pushing Homebrew's paths behind them.

For interactive shells, this means ~/.zprofile gives you a cleaner PATH order. But for non-interactive shells — the kind Mosh uses — ~/.zprofile never loads at all. You have to choose: slightly reordered PATH in interactive shells, or no Homebrew in non-interactive shells. The fix below picks the tradeoff that actually works.


Which Shell Config Files Load When

This is the core of the problem. Each shell has different rules about which config files it reads depending on how it's invoked.

zsh (macOS default since Catalina)

FileInteractive loginInteractive non-loginNon-interactive (SSH command)
~/.zshenvYesYesYes
~/.zprofileYes
~/.zshrcYesYes
~/.zloginYes

When Mosh runs ssh user@host 'mosh-server new', zsh only reads ~/.zshenv. Everything else is skipped.

bash

FileInteractive loginInteractive non-loginNon-interactive (SSH command)
~/.bash_profileYes
~/.bashrcVia .bash_profileYesDepends (see below)
~/.profileFallback if no .bash_profile

Bash has a quirk: it sources ~/.bashrc for non-interactive remote shells when it detects SSH (by checking for $SSH_CLIENT). But Mosh passes -tt to SSH to force a pseudo-terminal, which defeats this detection. So with Mosh specifically, bash does not source ~/.bashrc for the bootstrap command. The safest place for PATH setup is still ~/.bashrc (most SSH use cases work), but for guaranteed coverage you may need ~/.bash_profile to source ~/.bashrc, or use the $BASH_ENV variable.

fish

FileInteractive loginInteractive non-loginNon-interactive (SSH command)
config.fishYesYesYes

Fish loads ~/.config/fish/config.fish for every invocation. If you use fish and Homebrew is configured there, Mosh generally just works. Guard any output-producing commands with status is-interactive to avoid interfering with the SSH handshake.


The Fix

zsh (most Mac users)

Add Homebrew's PATH to ~/.zshenv on the Mac you're connecting to. SSH in and run:

Apple Silicon (M1/M2/M3/M4):

echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zshenv

Intel Mac:

echo 'eval "$(/usr/local/bin/brew shellenv)"' >> ~/.zshenv

brew shellenv sets PATH, HOMEBREW_PREFIX, HOMEBREW_CELLAR, and related variables. Putting it in ~/.zshenv ensures every shell type — including the non-interactive one Mosh uses — can find Homebrew-installed binaries.

You can keep the same line in ~/.zprofile too. For interactive login shells, ~/.zprofile runs after macOS's path_helper and gives you clean PATH ordering. For non-interactive shells, ~/.zshenv is the one that matters.

bash

If you've changed your Mac's default shell to bash, add Homebrew to ~/.bashrc:

echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.bashrc

Then make sure ~/.bash_profile sources it (if it doesn't already):

echo 'source ~/.bashrc' >> ~/.bash_profile

This covers interactive login shells (via .bash_profile.bashrc), interactive non-login shells (.bashrc directly), and most non-interactive SSH sessions.

fish

Fish typically handles this out of the box. If you installed Homebrew's PATH via fish_add_path, it's stored in universal variables and available everywhere. If not:

echo 'eval (/opt/homebrew/bin/brew shellenv)' >> ~/.config/fish/config.fish

Verify it worked

From another machine (or from Moshi), test the non-interactive PATH:

ssh user@your-mac 'which mosh-server'

If it prints /opt/homebrew/bin/mosh-server (Apple Silicon) or /usr/local/bin/mosh-server (Intel), you're set. If it prints nothing or "not found", the PATH isn't loading — double-check that the right config file exists and contains the brew shellenv line.

Now reconnect from Moshi with mode set to "Auto" or "Mosh." You should see the tmux session picker appear on connect:


What Else This Fixes

Any Homebrew-installed tool that runs from a non-interactive SSH session has the same problem. Common examples:

  • tmux — remote attach commands over SSH
  • node, bun, python — build scripts triggered remotely
  • git — if automation uses the Homebrew-installed version
  • claude — if you trigger Claude Code over SSH

The shell config fix resolves all of them at once.


Alternative: Set the Mosh Server Path in Moshi

If you'd rather not modify shell config files, you can tell Moshi exactly where mosh-server lives. Edit your connection and set the Mosh Server Path field to:

/opt/homebrew/bin/mosh-server

This bypasses PATH lookup entirely. It works, but fixing the shell config is better long-term — it solves the problem for every Homebrew tool, not just mosh-server.

From the command line, the equivalent is:

mosh --server=/opt/homebrew/bin/mosh-server user@your-mac

Related Articles

Resources