When setting up automated backups using rsync over SSH, many developers encounter the frustrating "protocol version mismatch -- is your shell clean?" error. This typically occurs when your remote shell environment outputs unexpected text before the rsync protocol communication begins.
Rsync expects a clean communication channel when establishing the connection. Any output from the remote shell (like MOTD messages, shell prompts, or profile scripts) can disrupt the protocol handshake. Even when you've silenced common offenders like PS1 and .hushlogin, other hidden culprits might remain.
Here's a step-by-step method to identify and eliminate all shell output sources:
# 1. Test with a minimal SSH command
ssh -T -i /path/to/key remoteuser@remotehost echo "TEST"
# 2. Check for forced command in authorized_keys
command="/bin/true" ssh-rsa AAAAB3NzaC1yc2E...
# 3. Verify shell initialization files
ssh -t -i /path/to/key remoteuser@remotehost "ls -la ~ | grep -E '\.bash|\.profile|\.zsh'"
# 4. Test with a null shell
rsync -avz -e "ssh -i /path/to/key -- /bin/sh -c 'exec rsync --server -vlogDtprze.iLsf . /path'" remoteuser@remotehost:/remote/dir /local/dir
When basic fixes don't work, try these professional techniques:
# Solution 1: Force protocol version 2 explicitly
rsync -avz -e "ssh -2 -i /path/to/key -o LogLevel=ERROR" remoteuser@remotehost:/remote/dir /local/dir
# Solution 2: Use a dedicated rsync wrapper script
# ~/.ssh/rsync-wrapper:
#!/bin/sh
exec /usr/bin/rsync --server --daemon --config=/etc/rsyncd.conf .
# Then in authorized_keys:
command="/home/user/.ssh/rsync-wrapper" ssh-rsa AAAAB3NzaC1yc2E...
Some environment variables can cause unexpected output. Test with this clean environment approach:
rsync -avz -e "ssh -i /path/to_key env -i /usr/bin/rsync --server --sender -vlogDtprze.iLsf . /remote/dir" remoteuser@remotehost:/remote/dir /local/dir
To confirm your environment is truly clean, use this diagnostic command:
ssh -i /path/to/key remoteuser@remotehost "echo 'SSH TEST'; echo 'ENV TEST' >&2" > /dev/null 2>&1
echo $?
# Should return 0 with no output
When automating backups using rsync over SSH, many administrators encounter the cryptic error:
protocol version mismatch -- is your shell clean?
This typically occurs when the remote shell outputs unexpected text before the rsync protocol communication begins. While the error suggests a version mismatch, the root cause is often environmental.
The key question "is your shell clean?" refers to unwanted output from:
- Shell prompts (PS1)
- Message of the Day (MOTD)
- Login banners
- Shell initialization scripts (.bashrc, .profile)
Basic mitigation steps should include:
# In remote user's ~/.bashrc
[ "$PS1" = "\\s-\\v\\\$ " ] || PS1=""
# Create empty hushlogin file
touch ~/.hushlogin
When basic fixes don't work, try these diagnostic commands:
# Test raw SSH connection
ssh -i keyfile user@host echo hello
# Verbose rsync output
rsync -avvvz -e "ssh -i keyfile" user@host:/path /local/path
# Check SSH protocol versions
ssh -V
sshd -V | grep OpenSSH
For legacy systems where protocol negotiation fails, explicitly force SSH protocol 2:
rsync -avz -e "ssh -2 -i /path/to/key" user@host:/remote /local
Additional SSH options to consider:
-o LogLevel=ERROR # Suppress connection messages
-o StrictHostKeyChecking=no # For automated environments
-o UserKnownHostsFile=/dev/null
For production backup scripts, consider this robust implementation:
#!/bin/bash
RSYNC_OPTS="-az --partial --delete --timeout=300"
SSH_OPTS="-2 -o BatchMode=yes -o StrictHostKeyChecking=no"
KEY_FILE="/path/to/backup_key"
rsync $RSYNC_OPTS -e "ssh $SSH_OPTS -i $KEY_FILE" \
backup@remote:/critical/data /local/backups/