| 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 | 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.
To copy through a bastion, use scp -J the same way as ssh -J. See SSH through a jump host for ~/.ssh/config aliases, separate keys, and multi-hop routes.
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; for password automation see pass an SSH password in a script):
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 |
