Master secure file copying over SSH: from basic syntax and practical examples to recursive transfers, bandwidth control, key authentication, Windows tools, and advanced troubleshooting.
SCP, which stands for Secure Copy Protocol, is a network protocol and command-line utility that enables the secure transfer of files between a local host and a remote host, or between two remote hosts, over an SSH (Secure Shell) connection. Every byte of data β file contents, filenames, and authentication credentials β is encrypted during transit, making SCP one of the simplest and most reliable ways to move files securely across networks.
The SCP protocol traces its origins to the BSD rcp (remote copy) command from the early 1980s. While rcp provided convenient remote file copying, it transmitted everything in plain text with no encryption and relied on the notoriously insecure .rhosts authentication model. When Tatu YlΓΆnen created SSH in 1995 at the Helsinki University of Technology, he included SCP as a secure replacement for rcp that leveraged SSH's encrypted transport layer. Since then, SCP has been bundled with virtually every SSH implementation, including OpenSSH β the most widely deployed SSH suite on Linux, macOS, and now Windows.
SCP is distinguished by its simplicity. Unlike SFTP, which provides a full interactive file management session with directory listings, permissions changes, and resume capabilities, SCP is designed to do one thing extremely well: copy files from point A to point B as fast as possible. You specify a source, a destination, and SCP handles the rest β establishing the SSH connection, authenticating, transferring the data, and closing the connection. There is no interactive shell, no session state, and no protocol overhead beyond what SSH itself requires.
Despite being considered somewhat legacy in favor of SFTP and rsync for complex workflows, SCP remains widely used in system administration, DevOps pipelines, and quick ad-hoc file transfers. Its command syntax is immediately familiar to anyone who has used the Unix cp command, and it requires no server-side configuration beyond a working SSH daemon β which is already present on the vast majority of Linux and Unix servers worldwide.
SCP protocol vs SCP command: The term "SCP" refers to both the wire protocol (SCP/RCP protocol running over SSH) and the scp command-line tool. Modern versions of OpenSSH (8.0+) actually use the SFTP protocol internally when you run the scp command, while keeping the familiar SCP command syntax unchanged. This gives you SFTP's improved reliability with SCP's simple interface.
Understanding how SCP operates under the hood helps you troubleshoot transfer problems, optimize performance, and make informed decisions about when to use SCP versus other transfer tools. At its core, SCP is a thin file-copying layer that rides on top of an SSH encrypted channel.
Every SCP transfer begins with a full SSH handshake. When you execute an scp command, the client first establishes a TCP connection to port 22 (or whichever port the SSH daemon is listening on) of the remote server. The SSH protocol then performs a key exchange using algorithms such as Curve25519 or Diffie-Hellman to establish a shared encryption secret. The server presents its host key for verification, and the client authenticates using a password, SSH key, or other configured method.
Once the encrypted channel is established and authentication succeeds, SCP does not open an interactive shell. Instead, the client invokes the scp binary on the remote server in either source mode (to send files) or sink mode (to receive files). The two SCP processes communicate through the encrypted SSH channel using a simple, line-oriented protocol: the source sends file metadata (permissions, size, filename) followed by the raw file data, and the sink acknowledges receipt or reports errors.
All data flowing through the SCP connection is protected by SSH's encryption layer. A typical modern SCP session uses AES-256-GCM or ChaCha20-Poly1305 for symmetric encryption, providing both confidentiality and integrity in a single authenticated encryption scheme. The SSH transport also applies message authentication codes (MACs) to every packet, ensuring that data cannot be tampered with in transit without detection. This means SCP provides the same level of cryptographic protection as a direct SSH session β enterprise-grade security with zero additional configuration.
SCP supports every authentication method available in SSH, because SCP is SSH. The most common methods are:
Client Server β β βββββ TCP SYN (port 22) ββββββββββΊβ βββββ TCP SYN-ACK ββββββββββββββββ βββββ TCP ACK ββββββββββββββββββββΊβ β β βββββ SSH Version String βββββββββΊβ βββββ SSH Version String ββββββββββ β β βββββ Key Exchange (KEX) βββββββββΊβ βββββ Key Exchange Reply ββββββββββ βββββ New Keys βββββββββββββββββββΊβ βββββ New Keys ββββββββββββββββββββ β β β==== Encrypted Channel ==========β β β βββββ Auth Request βββββββββββββββΊβ βββββ Auth Success ββββββββββββββββ β β βββββ Exec: scp -t /path βββββββββΊβ (sink mode) βββββ Ready (0x00) ββββββββββββββββ βββββ File Header (C0644 sz fn) ββΊβ βββββ Ack (0x00) ββββββββββββββββββ βββββ File Data ββββββββββββββββββΊβ βββββ Ack (0x00) ββββββββββββββββββ βββββ Session Close ββββββββββββββΊβ
The SCP command follows a syntax that mirrors the familiar Unix cp command, with the addition of remote host specifications using the user@host:path format. If you know how to use cp, you already know eighty percent of what you need to use scp.
# General SCP syntax scp [options] source destination # Copy local file to remote server scp localfile.txt user@remote-host:/remote/path/ # Copy remote file to local machine scp user@remote-host:/remote/path/file.txt ./local/path/ # Copy between two remote hosts scp user1@host1:/path/file.txt user2@host2:/path/
The source and destination arguments each take the form [user@]host:path for remote locations, or simply a local filesystem path for the local machine. If you omit the username, SCP uses your current local username. If you omit the remote path after the colon, SCP defaults to the user's home directory on the remote machine.
The colon (:) is what distinguishes a remote path from a local path. A path without a colon is always treated as local. A path with a colon before the file path is treated as remote. This is a common source of confusion for beginners β forgetting the colon will cause SCP to create a local file named user@host instead of connecting to the remote server.
Watch the colon! The command scp file.txt user@server/path/ (missing colon) will NOT connect to the remote server. It will copy file.txt to a local file literally named user@server/path/. Always use user@server:/path/ with a colon before the remote path.
Let us walk through the most common SCP use cases with real-world examples that you can adapt to your own environment. These examples cover single file transfers, multiple files, custom ports, and transfers involving paths with spaces.
# Upload a single file to the remote user's home directory scp report.pdf [email protected]:~ # Upload to a specific remote directory scp backup.sql [email protected]:/var/backups/ # Upload multiple files at once scp file1.txt file2.txt file3.log admin@server:/tmp/ # Upload a file and rename it on the remote server scp localdata.csv admin@server:/opt/data/imported-data.csv
# Download a file from the remote server to current directory
scp admin@server:/var/log/syslog .
# Download to a specific local directory
scp admin@server:/etc/nginx/nginx.conf C:\Users\Admin\Downloads\
# Download multiple files using brace expansion (bash)
scp admin@server:/var/log/{access,error}.log ./logs/
# Download using a wildcard (quotes prevent local shell expansion)
scp admin@server:"/var/log/app-*.log" ./logs/Many servers run SSH on a non-standard port for security. SCP uses the -P flag (uppercase P, unlike SSH's lowercase -p) to specify the port number:
# Connect using SSH port 2222 scp -P 2222 deploy.tar.gz admin@server:/opt/releases/ # Download from a server running SSH on port 8022 scp -P 8022 admin@server:/backups/db-dump.sql ./backups/
Port flag capitalization matters: SCP uses uppercase -P for the port, while the ssh command uses lowercase -p. This inconsistency is a historical artifact. If you accidentally use -p with SCP, it will be interpreted as "preserve file attributes" instead of setting the port number.
Copying entire directory trees is one of the most common SCP operations in system administration. The -r flag tells SCP to recursively copy directories, traversing the entire directory structure and transferring every file and subdirectory within it.
# Copy an entire directory to the remote server scp -r ./my-project/ admin@server:/opt/deployments/ # Download a remote directory to your local machine scp -r admin@server:/var/www/html/ ./website-backup/ # Recursive copy preserving file modification times and permissions scp -rp ./config-files/ admin@server:/etc/app-config/ # Recursive copy between two remote hosts scp -r admin@server1:/data/exports/ admin@server2:/data/imports/
By default, SCP does not preserve the original file modification times, access times, or permission modes. The -p flag (lowercase) instructs SCP to preserve these attributes on the transferred files. This is particularly important when deploying application code or configuration files where permissions matter for security and functionality.
When you copy a project directory recursively, SCP replicates the full tree structure on the destination:
my-project/ β /opt/deployments/my-project/ βββ src/ βββ src/ β βββ main.py β βββ main.py β βββ utils.py β βββ utils.py β βββ config/ β βββ config/ β βββ settings.json β βββ settings.json β βββ secrets.env β βββ secrets.env βββ tests/ βββ tests/ β βββ test_main.py β βββ test_main.py β βββ test_utils.py β βββ test_utils.py βββ requirements.txt βββ requirements.txt βββ README.md βββ README.md
Trailing slash behavior: Unlike rsync, SCP does not differentiate between ./my-project and ./my-project/ with a trailing slash. SCP always copies the directory itself, not just its contents. If you run scp -r ./my-project/ admin@server:/opt/, you will get /opt/my-project/ on the remote side β the directory is always included.
When transferring large files over shared network links, you may need to limit SCP's bandwidth consumption to avoid saturating the connection and impacting other services. SCP provides built-in options for bandwidth limiting and compression that give you fine-grained control over transfer performance.
The -l flag limits the bandwidth used by SCP, specified in kilobits per second (Kbit/s). Note that this is kilobits, not kilobytes β to limit to 1 MB/s, you would specify 8000 Kbit/s:
# Limit bandwidth to 5 Mbit/s (approximately 625 KB/s) scp -l 5000 large-backup.tar.gz admin@server:/backups/ # Limit to 1 Mbit/s for a low-priority background transfer scp -l 1000 dataset.zip admin@server:/data/ # Combine bandwidth limiting with recursive copy scp -rl 8000 ./log-archive/ admin@server:/storage/logs/
The -C flag enables SSH compression during the transfer. This passes the compression request to the SSH layer, which uses zlib to compress data before encryption. Compression is most effective for text-based files (source code, logs, CSV data, configuration files) and provides little to no benefit for already-compressed formats (ZIP, GZIP, JPEG, MP4).
On slow or high-latency connections, compression can dramatically speed up text file transfers by reducing the amount of data that needs to traverse the network. However, on fast local networks, compression adds CPU overhead that can actually slow down the transfer. Use compression judiciously based on your network speed and file types.
| Option | Purpose | Unit / Default | When to Use |
|---|---|---|---|
-l limit |
Cap transfer speed | Kbit/s | Shared links, production networks, background jobs |
-C |
Enable SSH compression | zlib / off | Text files over slow or high-latency links |
-c cipher |
Select encryption cipher | Negotiated | Performance tuning (AES-GCM with AES-NI hardware) |
-o "Compression=yes" |
Alternative compression toggle | SSH option | When passing multiple SSH options via -o |
While SCP works with password authentication, key-based authentication is the preferred method for both security and automation. SSH keys eliminate the need to type a password for every transfer, are immune to brute-force password attacks, and can be used in scripts and automated pipelines without embedding credentials in plain text.
If you do not already have an SSH key pair, you can generate one using the ssh-keygen utility that is bundled with OpenSSH on Windows 10+, Linux, and macOS:
# Generate an Ed25519 key (recommended β fast, secure, small) ssh-keygen -t ed25519 -C "yourname@yourmachine" # Generate an RSA 4096-bit key (wider compatibility) ssh-keygen -t rsa -b 4096 -C "yourname@yourmachine" # Keys are saved to: # Private: C:\Users\YourName\.ssh\id_ed25519 # Public: C:\Users\YourName\.ssh\id_ed25519.pub # Deploy the public key to the remote server ssh-copy-id -i ~/.ssh/id_ed25519.pub admin@server # Or manually append it type .ssh\id_ed25519.pub | ssh admin@server "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
If you have multiple SSH keys for different servers, use the -i flag to specify which private key SCP should use for authentication:
# Use a specific identity file for SCP scp -i C:\Users\Admin\.ssh\production_key backup.tar.gz deploy@prod-server:/releases/ # Combine with other options scp -i ~/.ssh/staging_key -P 2222 -rp ./build/ deploy@staging:/var/www/app/
SSH is strict about file permissions on key files. If your private key has overly permissive access rights, SSH (and therefore SCP) will refuse to use it. The correct permissions are:
~/.ssh/ drwx------ (700) β owner only βββ id_ed25519 -rw------- (600) β private key, owner read/write βββ id_ed25519.pub -rw-r--r-- (644) β public key, world readable βββ authorized_keys -rw------- (600) β authorized keys list βββ known_hosts -rw-r--r-- (644) β cached server fingerprints βββ config -rw------- (600) β SSH client configuration
Windows permissions: On Windows, the OpenSSH client also enforces key file permissions through NTFS ACLs. If SCP refuses your key with "Permissions for 'id_ed25519' are too open," right-click the file β Properties β Security β Advanced, disable inheritance, remove all users except your own account, and set your account to Full Control.
Beyond the basics, SCP provides several advanced options that are invaluable for debugging connection problems, optimizing transfer performance, navigating complex network topologies, and integrating SCP into automated workflows.
When SCP transfers fail or behave unexpectedly, the -v flag enables verbose output that shows every step of the SSH connection and authentication process. You can increase verbosity with -vv or -vvv for progressively more detailed diagnostic output:
# Standard verbose output β shows connection, auth, and transfer details scp -v report.pdf admin@server:/reports/ # Extra verbose β includes key exchange and cipher negotiation details scp -vvv data.csv admin@server:/imports/ # Specify cipher explicitly for performance or compatibility scp -c [email protected] largefile.bin admin@server:/data/ # Use a jump host (ProxyJump) to reach a server behind a bastion scp -J [email protected] file.txt [email protected]:/tmp/ # Pass arbitrary SSH options with -o scp -o "ConnectTimeout=10" -o "StrictHostKeyChecking=accept-new" file.txt admin@server:/tmp/
The encryption cipher used by SSH can significantly affect SCP transfer speeds, especially on fast networks where CPU becomes the bottleneck rather than bandwidth. Modern processors with AES-NI hardware acceleration can encrypt data at multi-gigabit speeds when using AES-based ciphers. Choosing the right cipher can mean the difference between 200 MB/s and 800 MB/s on a 10 Gbps link.
In enterprise environments, production servers are often placed behind bastion hosts (also called jump hosts) that serve as the sole entry point to the network. SCP supports transparent proxying through bastion hosts using the -J flag (OpenSSH 7.3+) or the -o ProxyJump option. The connection is end-to-end encrypted β the bastion host cannot read the data passing through it.
| Flag | Description | Example |
|---|---|---|
-r | Recursive β copy entire directories | scp -r ./dir/ user@host:/path/ |
-P port | Connect to specified SSH port | scp -P 2222 file user@host:/path/ |
-p | Preserve modification times, access times, modes | scp -p file user@host:/path/ |
-C | Enable compression (zlib) | scp -C file user@host:/path/ |
-l limit | Limit bandwidth in Kbit/s | scp -l 5000 file user@host:/path/ |
-i keyfile | Specify identity (private key) file | scp -i ~/.ssh/mykey file user@host:/ |
-c cipher | Select encryption cipher | scp -c [email protected] file user@host:/ |
-v / -vv / -vvv | Verbose output (increasing detail) | scp -vvv file user@host:/path/ |
-J jumphost | Connect via jump/bastion host | scp -J bastion file user@host:/path/ |
-o option | Pass SSH config options | scp -o "ConnectTimeout=10" file user@host:/ |
-q | Quiet mode β suppress progress meter | scp -q file user@host:/path/ |
-3 | Copy between two remote hosts via local | scp -3 user1@h1:/f user2@h2:/f |
Windows users have multiple options for using SCP, ranging from the built-in OpenSSH client to third-party tools with graphical interfaces. The choice depends on your workflow: command-line power users will prefer the native OpenSSH scp command or PuTTY's pscp.exe, while users who prefer visual file management can use WinSCP's drag-and-drop interface.
Windows 10 version 1803 and later (including Windows 11) include a built-in OpenSSH client that provides the scp command natively in PowerShell and Command Prompt. This is the same OpenSSH implementation used on Linux and macOS, so all the commands in this guide work identically on Windows. No installation is required β simply open PowerShell and start using scp.
To verify that the OpenSSH client is installed, run Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH.Client*' in PowerShell. If the State shows "Installed," you are ready to go. If it shows "NotPresent," install it with Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0 from an elevated PowerShell prompt.
PuTTY is a longstanding SSH client for Windows that includes pscp.exe β a command-line SCP tool. While the built-in OpenSSH is now preferred for most users, pscp remains useful if you already use PuTTY for SSH sessions and have saved session configurations. The syntax is similar to standard scp but with some PuTTY-specific differences, such as using -load "session_name" to reuse saved connections and -pw to specify a password on the command line (not recommended for security reasons).
WinSCP is a free, open-source file transfer client for Windows that supports SCP, SFTP, FTP, FTPS, WebDAV, and Amazon S3. It provides a dual-pane file manager interface where you can drag and drop files between your local machine and the remote server. WinSCP also includes powerful features like directory synchronization, a built-in text editor, scripting support, and integration with PuTTY's authentication agent (Pageant) for seamless key-based authentication.
When using WinSCP with the SCP protocol specifically, be aware that SCP mode provides faster raw transfer speeds but lacks some features available in SFTP mode, such as transfer resume, directory listing with file attributes, and remote file editing. For most users, WinSCP's SFTP mode is the better default choice, with SCP mode reserved for situations where maximum transfer speed is the priority or the server only supports SCP.
Windows path tips: When using SCP on Windows, remember that local paths use backslashes (C:\Users\Admin\file.txt) while remote Linux paths use forward slashes (/home/admin/file.txt). SCP handles this automatically β just use the native path format for each side. You can also use forward slashes for local paths in PowerShell; both formats work.
SCP, SFTP, and rsync are the three most common tools for transferring files over SSH. Each has distinct strengths and ideal use cases. Understanding their differences helps you choose the right tool for every situation.
| Feature | SCP | SFTP | rsync |
|---|---|---|---|
| Protocol | SCP over SSH | SFTP subsystem over SSH | rsync protocol over SSH |
| Interactive shell | No | Yes β full directory browsing | No |
| Transfer resume | No β restarts from scratch | Yes β built-in resume support | Yes β via --partial |
| Incremental sync | No β always copies full files | No (basic); SFTP clients may compare | Yes β delta transfer algorithm |
| Bandwidth limiting | Yes (-l) | Depends on client | Yes (--bwlimit) |
| Compression | Yes (-C) | Yes (SSH-level) | Yes (-z) |
| Preserve permissions | Yes (-p) | Yes | Yes (-a archive mode) |
| Delete remote extras | No | No (manual deletion) | Yes (--delete) |
| Dry run / preview | No | No | Yes (-n / --dry-run) |
| Windows built-in | Yes (OpenSSH) | Yes (OpenSSH) | No (requires WSL or third-party) |
| Speed (simple copy) | β β β β β Fastest | β β β β β Slightly slower | β β β β β Overhead on small files |
| Best for | Quick one-off copies | Interactive file management | Syncing directories, backups |
SCP transfers can fail for a variety of reasons, from authentication problems to network configuration issues. This section covers the most common error messages and their solutions to help you diagnose and resolve SCP problems quickly.
This is the most common SCP error and indicates that the server rejected your authentication credentials. Possible causes and fixes:
-i~/.ssh/authorized_keys file600 permissions (owner read/write only)PasswordAuthentication no in sshd_configsudoA timeout means the client could not reach the server within the default period. Common causes:
ping or nslookup-P porttracert (Windows) or traceroute (Linux) to identify where packets are being droppedThis error occurs when the server's SSH host key does not match the key stored in your known_hosts file. This can happen when a server has been reinstalled, its IP address has been reassigned to a different machine, or β in the worst case β someone is attempting a man-in-the-middle attack.
If you are certain the key change is legitimate (the server was rebuilt, for example), you can remove the old key entry and reconnect:
ssh-keygen -R hostnameC:\Users\YourName\.ssh\known_hosts and remove the line for the serverThis error indicates that the source file or destination path does not exist. Verify both paths carefully, remembering that remote paths are relative to the remote filesystem and local paths are relative to your current working directory. Use ssh user@host "ls -la /path/" to verify remote paths before attempting the SCP transfer.
A "broken pipe" error means the SSH connection was unexpectedly terminated during the transfer. This is typically caused by network instability, SSH session timeouts, or the remote server dropping the connection. For large transfers over unreliable networks, consider using rsync (which supports resume) or SFTP instead of SCP. You can also add SSH keepalive options to prevent idle-timeout disconnections: scp -o "ServerAliveInterval=60" -o "ServerAliveCountMax=3" file user@host:/path/.
Security warning: Never use -o "StrictHostKeyChecking=no" in production environments to bypass host key verification. This disables a critical security check that protects against man-in-the-middle attacks. If you encounter host key warnings, investigate the cause before proceeding. Use StrictHostKeyChecking=accept-new instead if you need to auto-accept keys for new hosts while still rejecting changed keys.
SCP remains one of the most efficient and straightforward tools for secure file transfers. Its simplicity is its greatest strength β a single command can move files across the globe through an encrypted SSH tunnel with no additional setup beyond a working SSH daemon. Here are the key practices to follow for reliable, secure, and performant SCP usage:
~/.ssh/config) to define host aliases, default ports, identity files, and jump hosts for frequently accessed servers β this simplifies SCP commands significantly.You are now SCP-ready! With the knowledge from this guide, you can confidently use SCP to securely transfer files between any combination of local and remote machines, optimize transfers for your network conditions, troubleshoot common problems, and choose the right tool (SCP, SFTP, or rsync) for every use case. For deeper exploration of related topics, check out our SFTP Guide for interactive file management, our Server Management Guide for remote administration, and our File Sync Guide for directory synchronization strategies.