scp Command in Linux: Syntax, Options & Secure File Copy Over SSH

Deepak Prasad
Tested on Ubuntu 25.04 (Plucky Puffin)
Package openssh-client
openssh-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):

text
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 ... target

scp 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):

bash
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.txt

Sample output:

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.txt

Remove 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:

bash
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.txt

Sample output:

output
testfile.txt 100%   21     0.0KB/s   00:00
scp lab file content

Use 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:

bash
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 f

Sample output:

output
nested.txt 100%    7     0.0KB/s   00:00
/tmp/scp-dst/testdir/nested.txt

Trailing 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:

bash
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.txt

Sample output:

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:

bash
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.txt

Sample output:

output
testfile.txt 100%   21     0.0KB/s   00:00

Remove 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:

bash
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.txt

Sample output:

output
testfile.txt 100%   21     0.0KB/s   00:00

Replace 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:

bash
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.txt

Sample output:

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:

bash
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 -12

Sample output:

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:

bash
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-b

Sample output:

output
hop.txt 100%   16     0.0KB/s   00:00
remote hop test

Both 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:

bash
scp -O -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no \
  /tmp/scp-src/testfile.txt $(whoami)@127.0.0.1:/tmp/scp-dst/legacy.txt

Sample output:

output
testfile.txt 100%   21     0.0KB/s   00:00

Use -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
  • You need a one-off secure copy and SSH is already working
  • Scripts copy a few files with key-based auth (-B, -i)
  • Operators know SSH destination syntax (user@host:path)
  • You pull or push tarballs, configs, or logs between two paths quickly
  • You need incremental sync, resume, or delta transfers → rsync
  • You browse directories interactively → SFTP or ssh with sftp subsystem
  • You mirror large trees on a schedule → rsync or dedicated backup tools
  • You automate many parallel hosts → parallel SSH with rsync

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):

bash
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?
bash
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

Rohan Timalsina

is a technical writer and Linux enthusiast who writes practical guides on Linux commands and system administration. He focuses on simplifying complex topics through clear explanations.

  • Linux
  • HTML5
  • JavaScript
  • Web Design
  • Front-end Web Development