| Tested on | Ubuntu 25.04 (Plucky Puffin) |
|---|---|
| Package | openssh-clientopenssh-clients |
| Applies to | Ubuntu, Debian, Kali Linux, Linux Mint, Pop!_OS, Raspberry Pi OS, RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora, Arch Linux |
| Privilege | sudo or root |
| Man page | scp(1) |
| Scope | scp copies files and directories between hosts over SSH using the SFTP protocol by default. It supports recursion, bandwidth limits, identity keys, and ssh_config options on Ubuntu and most Linux systems. |
| Related guides | Passwordless SSH authentication Linux commands |
scp — quick reference
Copy patterns
Remote paths use user@host:path. Brackets around IPv6 addresses: user@[::1]:path. Local paths are ordinary filesystem paths.
| When to use | Command |
|---|---|
| Copy a file to a remote host | scp /local/file user@host:/remote/dir/ |
| Copy a file from a remote host to local | scp user@host:/remote/file /local/dir/ |
| Copy between paths on the same host via SSH (localhost lab) | scp /tmp/src/file $(whoami)@127.0.0.1:/tmp/dst/ |
| Copy a directory recursively | scp -r /local/dir user@host:/remote/dir/ |
| Copy from one remote host to another through this client | scp -3 user1@host1:/path user2@host2:/path |
Transfer options
| When to use | Command |
|---|---|
| Preserve modification time, access time, and modes | scp -p /local/file user@host:/remote/ |
| Quiet mode — hide progress meter and most SSH warnings | scp -q /local/file user@host:/remote/ |
| Verbose — debug connection and authentication | scp -v /local/file user@host:/remote/ |
| Enable compression during transfer | scp -C /local/file user@host:/remote/ |
| Limit bandwidth (Kbit/s) | scp -l 8000 /local/file user@host:/remote/ |
| Do not prompt for passwords (batch / key-based) | scp -B /local/file user@host:/remote/ |
| Use IPv4 addresses only | scp -4 /local/file user@host:/remote/ |
| Use IPv6 addresses only | scp -6 /local/file user@host:/remote/ |
| Remote-to-remote: disable agent forwarding for second hop | scp -A /local/file user@host:/remote/ |
| Copy directories recursively (required for folders) | scp -r /local/dir user@host:/remote/ |
| Reproduce directories as symlinks to non-directories (rare) | scp -r -R /local/dir user@host:/remote/ |
SSH connection options
Passed through to ssh; same semantics as ssh and ssh_config.
| When to use | Command |
|---|---|
| SSH port when remote sshd is not on 22 | scp -P 2222 /local/file user@host:/remote/ |
| Identity (private key) file for public-key auth | scp -i ~/.ssh/id_ed25519 /local/file user@host:/remote/ |
| Alternate ssh client config file | scp -F ~/.ssh/config.d/site.conf /local/file user@host:/remote/ |
| Proxy jump host (bastion) | scp -J bastion user@internal:/remote/file /local/ |
| Pass a single ssh_config option | scp -o StrictHostKeyChecking=no /local/file user@host:/remote/ |
| Pass ssh_config option (BatchMode for scripts) | scp -o BatchMode=yes -i key /local/file user@host:/remote/ |
| Select encryption cipher | scp -c aes128-ctr /local/file user@host:/remote/ |
| Path to ssh program (non-default) | scp -S /usr/bin/ssh /local/file user@host:/remote/ |
Protocol selection (OpenSSH 9.x)
| When to use | Command |
|---|---|
| Default transfer — SFTP subsystem (OpenSSH 9 default) | scp /local/file user@host:/remote/ |
| Force legacy SCP protocol (old servers without SFTP) | scp -O /local/file user@host:/remote/ |
| Remote SFTP server path (non-default subsystem) | scp -D /usr/lib/openssh/sftp-server /local/file user@host:/remote/ |
| Pass SFTP subsystem option | scp -X option=value /local/file user@host:/remote/ |
Deprecated protocol versions
| When to use | Command |
|---|---|
| Deprecated — SSH protocol version 1 (avoid) | scp -1 /local/file user@host:/remote/ |
| Deprecated — force SSH protocol version 2 | scp -2 /local/file user@host:/remote/ |
scp — command syntax
Usage text from scp with no arguments on Ubuntu 25.04 (OpenSSH_9.9p1):
usage: scp [-346ABCOpqRrsTv] [-c cipher] [-D sftp_server_path] [-F ssh_config]
[-i identity_file] [-J destination] [-l limit] [-o ssh_option]
[-P port] [-S program] [-X sftp_option] source ... targetscp does not edit local account databases; it uses SSH for authentication and transport. Destination paths need write permission on the remote (or local) side. See sudo on the remote host when copying into protected directories.
scp — command examples
Essential Copy a file to localhost over SSH (safe lab)
Practice scp without a second machine by targeting 127.0.0.1 and paths under /tmp.
Prepare a file and copy it (key-based auth avoids password prompts in scripts):
mkdir -p /tmp/scp-src /tmp/scp-dst
echo 'scp lab file content' > /tmp/scp-src/testfile.txt
scp -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=accept-new \
/tmp/scp-src/testfile.txt $(whoami)@127.0.0.1:/tmp/scp-dst/
ls -l /tmp/scp-dst/testfile.txtSample output:
testfile.txt 100% 21 0.0KB/s 00:00
-rw-r--r-- 1 root root 21 Jul 1 14:39 /tmp/scp-dst/testfile.txtRemove lab dirs when finished: rm -rf /tmp/scp-src /tmp/scp-dst.
Essential Pull a file from remote to local
Download reverses the argument order — remote source first, local directory last.
Run the command:
scp -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no \
$(whoami)@127.0.0.1:/tmp/scp-dst/testfile.txt /tmp/scp-dst/pull-test.txt
cat /tmp/scp-dst/pull-test.txtSample output:
testfile.txt 100% 21 0.0KB/s 00:00
scp lab file contentUse this pattern after backups: scp user@server:/var/backups/db.sql.gz ./.
Essential Copy a directory recursively (-r)
Folders need -r or scp refuses the transfer.
Run the command:
mkdir -p /tmp/scp-src/testdir
echo nested > /tmp/scp-src/testdir/nested.txt
scp -r -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no \
/tmp/scp-src/testdir $(whoami)@127.0.0.1:/tmp/scp-dst/
find /tmp/scp-dst/testdir -type fSample output:
nested.txt 100% 7 0.0KB/s 00:00
/tmp/scp-dst/testdir/nested.txtTrailing slash on the source changes whether the directory itself or only its contents is copied — test with ls on the destination before deleting production files.
Common Preserve timestamps and permissions (-p)
Backups and release artifacts often need the same mtime and mode on the destination.
Run the command:
touch -d '2024-01-15 10:00:00' /tmp/scp-src/testfile.txt
chmod 640 /tmp/scp-src/testfile.txt
scp -p -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no \
/tmp/scp-src/testfile.txt $(whoami)@127.0.0.1:/tmp/scp-dst/preserved.txt
stat -c '%a %y' /tmp/scp-src/testfile.txt /tmp/scp-dst/preserved.txtSample output:
preserved.txt 100% 21 0.0KB/s 00:00
640 2024-01-15 10:00:00.000000000 +0000
640 2024-01-15 10:00:00.000000000 +0000-p maps to ssh/sftp preserve flags; it does not preserve ownership without root on both ends.
Common Use a specific identity file (-i)
Deploy keys and per-environment keys use -i to pick the private key.
Run the command:
ssh-keygen -t ed25519 -f /tmp/scp-demo-key -N '' -q
cat /tmp/scp-demo-key.pub >> ~/.ssh/authorized_keys
scp -i /tmp/scp-demo-key -o StrictHostKeyChecking=no \
/tmp/scp-src/testfile.txt $(whoami)@127.0.0.1:/tmp/scp-dst/keyed.txt
grep -vFf /tmp/scp-demo-key.pub ~/.ssh/authorized_keys > /tmp/ak.tmp && mv /tmp/ak.tmp ~/.ssh/authorized_keys
rm -f /tmp/scp-demo-key /tmp/scp-demo-key.pub /tmp/scp-dst/keyed.txtSample output:
testfile.txt 100% 21 0.0KB/s 00:00Remove the demo key from authorized_keys after testing, as shown in the cleanup commands.
Common Non-default SSH port and ssh_config option (-P, -o)
When sshd listens on a high port or you need BatchMode for CI, pass SSH flags through scp.
Run the command:
scp -P 22 -o BatchMode=yes -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no \
/tmp/scp-src/testfile.txt $(whoami)@127.0.0.1:/tmp/scp-dst/port22.txtSample output:
testfile.txt 100% 21 0.0KB/s 00:00Replace 22 with your server's port. BatchMode=yes fails fast instead of prompting when keys are missing.
Common Bandwidth limit and quiet mode (-l, -q)
Throttle large copies on shared links or hide progress in cron logs.
Run the command:
scp -q -l 8 -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no \
/tmp/scp-src/testfile.txt $(whoami)@127.0.0.1:/tmp/scp-dst/quiet.txt
echo exit:$?
ls /tmp/scp-dst/quiet.txtSample output:
exit:0
/tmp/scp-dst/quiet.txt-l is Kbit/s (8 ≈ 1 KB/s). -q suppresses the progress meter; errors still print to stderr.
Advanced Verbose transfer for authentication failures (-v)
When scp hangs or denies access, verbose SSH output shows where it stopped.
Run the command:
scp -v -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no \
/tmp/scp-src/testfile.txt $(whoami)@127.0.0.1:/tmp/scp-dst/verbose.txt 2>&1 | head -12Sample output:
Executing: program /usr/bin/ssh host 127.0.0.1, user root, command sftp
OpenSSH_9.9p1 Ubuntu-3ubuntu3.2, OpenSSL 3.4.1 11 Feb 2025
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Connecting to 127.0.0.1 [127.0.0.1] port 22.
debug1: Connection established.
debug1: identity file /root/.ssh/id_ed25519 type 3
debug1: Authenticating to 127.0.0.1:22 as 'root'
debug1: Will attempt key: /root/.ssh/id_ed25519 ED25519 SHA256:...OpenSSH 9 uses SFTP for default scp; the log line command sftp is expected.
Advanced Copy between two remotes through this host (-3)
Without -3, scp streams directly host-to-host. With -3, data flows through your machine — useful when firewalls block peer SSH.
Run the command:
echo 'remote hop test' > /tmp/scp-a/hop.txt
scp -3 -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no \
$(whoami)@127.0.0.1:/tmp/scp-a/hop.txt $(whoami)@127.0.0.1:/tmp/scp-b/
cat /tmp/scp-b/hop.txt
rm -rf /tmp/scp-a /tmp/scp-bSample output:
hop.txt 100% 16 0.0KB/s 00:00
remote hop testBoth hosts prompt for authentication unless keys are configured; -B avoids password prompts only when keys work for both sides.
Advanced Force legacy SCP protocol (-O)
Older appliances lack the SFTP subsystem. -O selects the classic scp protocol.
Run the command:
scp -O -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no \
/tmp/scp-src/testfile.txt $(whoami)@127.0.0.1:/tmp/scp-dst/legacy.txtSample output:
testfile.txt 100% 21 0.0KB/s 00:00Use -O only when SFTP fails; the legacy path needs a remote shell for globbing and is harder to harden.
scp — when to use / when not
| Use scp when | Use something else when |
|---|---|
|
|
scp vs rsync and SFTP
| scp | rsync | SFTP | |
|---|---|---|---|
| Primary job | Simple copy | Sync with deltas | Interactive file session |
| Resume / partial | No | Yes (with flags) | Depends on client |
| Default in OpenSSH 9 | SFTP backend | Uses SSH (often rsync daemon or SSH) | SSH subsystem |
| Best for | Quick copy, small scripts | Backups, large trees | Manual exploration |
| Recursive dirs | -r |
Built-in | put -r in client |
See scp vs rsync comparison when you need to choose between one-off copy and repeated sync.
scp — interview corner
What is scp in Linux?
scp (secure copy) copies files between hosts over SSH. Syntax mirrors cp but adds user@host:path for remote ends.
Modern OpenSSH uses the SFTP protocol for transfers by default; legacy scp protocol is selected with -O. Authentication is the same as ssh — passwords, keys, or agent.
A strong answer is:
"scp is OpenSSH's secure copy — local-to-remote, remote-to-local, or remote-to-remote. It rides SSH; on current OpenSSH the default backend is SFTP, not the old scp wire protocol."
When do you use scp instead of rsync?
Use scp for occasional copies — a config file, a build artifact, a one-line cron job. It is simple and everywhere openssh-client is installed.
Use rsync when you need only changed blocks, --delete, dry-run, or repeatable large-tree sync.
A strong answer is:
"scp for quick one-shot copies when SSH works; rsync when I need deltas, resume, or mirroring large directories."
How do you specify a non-default SSH port with scp?
scp uses capital -P (unlike ssh's -p for port):
scp -P 2222 file user@host:/remote/Pair with -i for keys and -o StrictHostKeyChecking=accept-new for first connect in automation.
A strong answer is:
"Capital -P for port with scp — for example -P 2222. I combine it with -i and ssh -o options passed through -o."
How do you copy a directory with scp?
scp -r /local/dir user@host:/remote/path/-r is required for directories. Trailing slashes affect whether the directory name is included on the destination — verify with a small test tree first.
A strong answer is:
"scp -r for directories; watch trailing slashes so I copy the folder vs its contents intentionally."
What changed about scp in recent OpenSSH versions?
OpenSSH 8.8+ made SFTP the default transfer mode inside scp. The old scp protocol remains available as scp -O for legacy servers.
You may see command sftp in scp -v output — that is normal on OpenSSH 9.
A strong answer is:
"Modern scp uses SFTP under the hood; -O forces legacy scp for old gear. Verbose logs show sftp as the remote command — expected on OpenSSH 9."
Troubleshooting
When Connection refused appears, confirm sshd is listening on the server with ss -ltn 'sport = :22' before changing client flags; see the ss command for port filters.
| Symptom | Likely cause | Fix |
|---|---|---|
Permission denied (publickey,password) |
No valid auth | Set up keys (ssh-keygen, authorized_keys) or use correct -i |
lost connection after password |
-B with password-only host |
Remove -B or configure keys |
not a regular file / omitting dirs |
Missing -r |
Add scp -r for directories |
Connection refused |
Wrong host or port | Check ss -ltn 'sport = :22' on server; use -P |
scp: ambiguous target |
Colon in local path | Quote path or use ./ prefix for local files |
| SFTP fails on old device | Server lacks sftp-server | Try scp -O (legacy protocol) |
| Very slow on fast LAN | -l limit or -C on compressed data |
Remove -l; skip -C for zip/png/isos |
