Rsync vs scp: rsync remembers, scp forgets
One line, every flag annotated — the resume incantation, the delta-transfer gap, and the three cases where scp still wins.
rsync for backups, big trees, anything you will run more than once — scp for one small file, once.
scp cannot resume: a drop at 900 MB of 1 GB — 100 MB short — restarts from zero. rsync with --partial --append-verify turns that restart into a pause.
On re-runs rsync moves only the changed blocks; scp re-sends everything. The one flag to take away: --partial.
THE ONE LINE, ANNOTATED
Most people only ever need this — every flag labelled, in order:
the trailing slash trips everyone once — rsync even warns "no bytes transferred" when you meant the other form
WHAT THE STATE DIFFERENCE BUYS
scp does one thing: open an SSH channel, stream the bytes, close. No state between runs, so a transfer that dies at 90% restarts from zero and re-sends the whole 1,000 MB. rsync is a synchronisation tool that happens to use SSH as transport: before sending it builds a checksum list of the destination (the rolling-checksum delta algorithm) and transmits only the blocks that differ. Run the same command twice and the second pass moves almost nothing — which also makes rsync the natural tool for keeping two directories in sync: schedule it and each run copies just the deltas. The practical consequences:
- Interruptions: rsync resumes; scp restarts the file.
- Second copies: rsync sends only changes; scp re-sends everything.
- Deletions: rsync can mirror deletions with
--delete; scp cannot. - Filtering: rsync has
--excludepatterns; scp copies everything you point at. - Dry runs: rsync shows what it would do with
--dry-run; scp offers nothing.
IS RSYNC FASTER?
For a first-time copy of one large file over a fast link, they are close — both saturate SSH, and the checksum pass adds only a small overhead. The gap opens in three places:
- Small files in bulk. rsync pipelines directory walks and can reuse one connection; older scp setups spawned work per file. Thousands of little files — a
node_modules, a WordPress install — finish noticeably faster with rsync. - Re-runs. Copy a 4.0 GB file where 50 MB changed and rsync moves roughly 50 MB; scp moves 4 GB again.
- Compression.
-zcompresses in flight, which helps on slow WAN links.
You can time both yourself — the command is identical in shape, and the re-run is where the answer lives:
# same file, same server, both over SSH
time scp bigfile.tar.gz user@server:/tmp/
time rsync -avh --progress bigfile.tar.gz user@server:/tmp/
# re-run both: scp re-copies, rsync verifies and sends ~nothing
time scp bigfile.tar.gz user@server:/tmp/
time rsync -avh --progress bigfile.tar.gz user@server:/tmp/
THE RESUME INCANTATION
No, scp cannot resume an interrupted transfer — no flag, no trick. rsync's whole design assumes the transfer will be interrupted sometimes:
rsync -avh --partial --append-verify --progress bigfile.tar.gz user@server:/srv/backup/
--partialkeeps the half-written file instead of deleting it.--append-verifyresumes by appending, then checksum-verifies the appended region — safe against a corrupt partial file, unlike the old plain--append.--progressshows you where it picked up.
Wrapped in a retry loop, this is a set-and-forget backup over even a hostile connection:
until rsync -avh --partial --append-verify --progress \
./bigfile.tar.gz user@server:/srv/backup/; do
sleep 5
done
verify: run the same rsync again → it verifies and sends ~nothing
WHEN scp STILL WINS
- One small file, once. Typing
scp app.conf user@host:/etc/myapp/is shorter than any rsync invocation, and there is nothing to resume. - rsync is missing on the far end. rsync needs its binary on both sides. Many minimal containers and appliances ship scp's SFTP server but not rsync.
- You don't want an rsync daemon exposed. Rare, but some environments lock down the rsync daemon specifically.
One subtlety worth knowing: the OpenSSH project deprecated scp's original protocol years ago, and modern scp actually speaks SFTP underneath. That fixed a path-escaping quirk, but it changed nothing about the two limitations that matter — no resume, no delta transfer. The protocol change does not make scp rsync. And if your question is really "rsync vs cp": cp is the local-only equivalent of scp — no resume, no delta, no attributes unless you add flags — and for local one-shots it is fine.
THE DANGEROUS ONE
--delete mirrors deletions too — it removes files at the destination that are gone at the source. Powerful for mirrors, dangerous everywhere else. Dry-run anything that carries it:
rsync -avh --delete --dry-run src/ user@server:/srv/dest/ # review
rsync -avh --delete src/ user@server:/srv/dest/ # then commit
verify: the --dry-run pass prints the deletion list and changes nothing
For a daily or weekly sync, drop rsync into a systemd timer and let it copy only the deltas — the journal is where the runs leave their story.
THE VERDICT TABLE
| scp | rsync | |
|---|---|---|
| Ships with OpenSSH | Yes | Yes (both ends needed) |
| Resume interrupted transfer | No | Yes (--partial) |
| Delta transfer on re-runs | No | Yes |
| Preserve permissions/symlinks | Partially | Fully (-a) |
| Exclude patterns | No | --exclude |
| Dry run | No | --dry-run |
| Mirror deletions | No | --delete |
| Best for | Quick one-off copies | Backups, syncs, bulk trees |
Default to rsync for backups, big trees, anything over a link that can drop, and anything you will run more than once. Use scp when the command is shorter than the thought. If you take one flag away, take --partial — it converts every future dropped connection from a restart into a pause.
end of the copy page · nothing fetched · everything local