ZetCode

Linux scp Command

last modified October 23, 2026

The scp (secure copy) command in Linux copies files and directories between hosts over SSH. Data and passwords are encrypted, and authentication uses the same methods as ssh, such as passwords or key pairs.

The syntax resembles cp: scp [options] source target. A remote location is written as user@host:path; a relative path after the colon is resolved against the remote user's home directory, and an empty path means the home directory itself. Since OpenSSH 9.0, scp uses the SFTP protocol for transfers by default; the -O option selects the legacy SCP protocol for old servers.

In the examples, the remote machine is called server and we log in as user jano with an SSH key, so no password prompts appear.

Copying a file to a remote host

To upload a file, we give a local source and a remote target.

scp notes.txt jano@server:

The file is copied to the home directory of jano on server. When run in a terminal, scp shows a progress line with the file name, percentage, size, speed, and time. We verify the upload by running ls remotely with ssh.

$ scp notes.txt jano@server:
notes.txt                                     100%   14    21.5KB/s   00:00    
$ ssh jano@server ls -l
total 4
-rw-r----- 1 jano jano 14 Oct 23 10:50 notes.txt

Copying to a specific path

The path after the colon sets the target directory or file name.

scp todo.txt jano@server:/tmp/todo-backup.txt

The file is copied to /tmp on the remote host under a new name. If the target is an existing directory, the original name is kept. Existing files are overwritten without a warning.

$ scp todo.txt jano@server:/tmp/todo-backup.txt
$ ssh jano@server cat /tmp/todo-backup.txt
buy milk

Copying a file from a remote host

To download, the remote location is the source and a local path the target.

scp jano@server:/etc/hostname downloads/
scp jano@server:/etc/os-release downloads/release.txt

The first command keeps the remote file name; the second saves the file under a different name. To copy into the current directory, use . as the target.

$ mkdir downloads
$ scp jano@server:/etc/hostname downloads/
$ scp jano@server:/etc/os-release downloads/release.txt
$ ls downloads
hostname
release.txt
$ cat downloads/hostname
server

Copying multiple files

Several sources can be given at once; the target must then be a directory.

scp notes.txt todo.txt ideas.txt jano@server:docs/
scp 'jano@server:docs/*.txt' downloads/

Local wildcards are expanded by the local shell. A wildcard in a remote path must be quoted so that the local shell leaves it alone and it is expanded on the remote side.

$ ssh jano@server mkdir docs
$ scp notes.txt todo.txt ideas.txt jano@server:docs/
$ scp 'jano@server:docs/*.txt' downloads/
$ ls downloads
hostname
ideas.txt
notes.txt
release.txt
todo.txt

Copying directories

The -r option copies directories recursively.

scp -r project jano@server:

The whole project directory, including its subdirectories, is created in the remote home directory. Symbolic links are followed during the copy.

$ scp -r project jano@server:
README.md                                     100%   10    18.0KB/s   00:00    
app.py                                        100%   12    33.4KB/s   00:00    
$ ssh jano@server find project
project
project/README.md
project/src
project/src/app.py

Preserving times and modes

The -p option preserves the modification and access times and the permission bits of the original file.

scp notes.txt jano@server:plain.txt
scp -p notes.txt jano@server:preserved.txt

Without -p, the copy gets the current time as its modification time. With -p, the original date is kept. Note that the lowercase -p preserves attributes, while the uppercase -P sets the port. Ownership is not preserved; files belong to the user we log in as.

$ ls -l notes.txt
-rw-r----- 1 jano jano 14 Sep  1 08:00 notes.txt
$ scp notes.txt jano@server:plain.txt
$ scp -p notes.txt jano@server:preserved.txt
$ ssh jano@server ls -l plain.txt preserved.txt
-rw-r----- 1 jano jano 14 Oct 23 10:50 plain.txt
-rw-r----- 1 jano jano 14 Sep  1 08:00 preserved.txt

Custom port and identity file

The -P option connects to a non-standard SSH port, and -i selects the private key used for authentication.

scp -P 2222 todo.txt jano@server:
scp -i ~/.ssh/id_ed25519 ideas.txt jano@server:

Our server listens on ports 22 and 2222. The key file given with -i must not be readable by other users, or SSH refuses to use it.

$ scp -P 2222 todo.txt jano@server:
$ scp -i ~/.ssh/id_ed25519 ideas.txt jano@server:
$ ssh jano@server ls todo.txt ideas.txt
ideas.txt
todo.txt

Limiting bandwidth and compression

The -l option limits the bandwidth in Kbit/s, and -C enables compression.

scp -l 4000 data.bin jano@server:
scp -C log.txt jano@server:

A limit of 4000 Kbit/s corresponds to about 500 KB/s, as the speed in the progress line shows. Limiting is useful to leave capacity for other traffic. Compression helps with text such as logs on slow networks, but it wastes CPU time on fast links and on already compressed data.

$ scp -l 4000 data.bin jano@server:
data.bin                                      100% 1953KB 546.7KB/s   00:03    
$ scp -C log.txt jano@server:
log.txt                                       100% 1259KB  21.1MB/s   00:00    

Quiet and verbose modes

The -q option suppresses the progress meter and warnings, while -v prints debugging messages about the connection.

scp -q data.bin jano@server:
scp -v notes.txt jano@server: 2>&1 | grep -E "Authenticated|Sending|Exit status"

Quiet mode is suitable for scripts. The verbose output is long, so we filter a few lines: they show the authentication method and that the transfer uses the SFTP subsystem. Verbose mode helps to diagnose connection and authentication problems.

$ scp -q data.bin jano@server:
$ scp -v notes.txt jano@server: 2>&1 | grep -E "Authenticated|Sending|Exit status"
Authenticated to server ([172.18.0.2]:22) using "publickey".
debug1: Sending environment.
debug1: Sending subsystem: sftp
debug1: Exit status 0

Using SSH configuration aliases

scp reads the SSH client configuration in ~/.ssh/config, so host aliases with their user names, ports, and keys work as well.

scp notes.txt web:from-alias.txt

The web alias stands for user jano on server, port 2222, with a specific key. The command is shorter and less error-prone than spelling out all the options.

$ cat ~/.ssh/config
Host web
    HostName server
    User jano
    Port 2222
    IdentityFile ~/.ssh/id_ed25519
$ scp notes.txt web:from-alias.txt
$ ssh web ls from-alias.txt
from-alias.txt

Copying between two remote hosts

Both the source and the target can be remote. The -3 option routes the data through the local machine.

scp -3 jano@server:notes.txt web:/tmp/relay.txt

With -3, the two remote hosts do not need to be able to reach or authenticate to each other; the local machine connects to both. Since OpenSSH 8.7, this is also the default behaviour.

$ scp -3 jano@server:notes.txt web:/tmp/relay.txt
$ ssh web cat /tmp/relay.txt
meeting notes

Common errors

scp reports missing files and permission problems on either side.

scp missing.txt jano@server:
scp jano@server:missing.txt .
scp notes.txt jano@server:/root/

The first two commands refer to files that do not exist locally or remotely. The last one fails because a regular user cannot write to the home directory of root. A frequent mistake is forgetting the colon: the command scp notes.txt jano@server creates a local file named jano@server.

$ scp missing.txt jano@server:
scp: stat local "missing.txt": No such file or directory
$ scp jano@server:missing.txt .
scp: missing.txt: No such file or directory
$ scp notes.txt jano@server:/root/
scp: dest open "/root/notes.txt": Permission denied
scp: failed to upload file notes.txt to /root/

Best practices for scp

Source

scp manual page

In this article, we have used the scp command to copy files and directories between local and remote hosts, preserve attributes, use custom ports, keys, and host aliases, limit bandwidth, and diagnose transfers.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Linux tutorials.