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.
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
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:
--delete; scp cannot.--exclude patterns; scp copies everything you point at.--dry-run; scp offers nothing.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:
node_modules, a WordPress install — finish noticeably faster with rsync.-z compresses 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/
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/
--partial keeps the half-written file instead of deleting it.--append-verify resumes by appending, then checksum-verifies the appended region — safe against a corrupt partial file, unlike the old plain --append.--progress shows 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
scp app.conf user@host:/etc/myapp/ is shorter than any rsync invocation, and there is nothing to resume.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.
--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.
| 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