HomeTopicsSCP & SSH Copying › The scp Command

The scp Command, Mastered

Most people use scp at about ten percent of its capability: one memorized incantation, repeated forever, with a trip to a search engine every time the situation deviates. That is a shame, because the whole tool can be learned in an afternoon. There are perhaps ten flags worth knowing, one syntax rule that explains everything, and a short list of mistakes that every administrator makes exactly once.

This is the cookbook version: the anatomy of the command, the flags that matter, a dozen worked one-liners you can copy straight into a terminal, and the gotchas laid out before they cost you anything. It is part of our SCP & SSH Copying series — the protocol story behind the command is told earlier in the series, and the things no flag can fix live in SCP's limitations.

Anatomy of an scp Command

Every scp command reads the same way: source first, destination last, exactly like cp. Either side (or, with care, both) can be remote, and what makes a path remote is the colon:

scp [flags] LOCAL-PATH        user@host:REMOTE-PATH     # upload
scp [flags] user@host:REMOTE-PATH   LOCAL-PATH          # download
scp [flags] user@hostA:PATH   user@hostB:PATH           # remote to remote

Three details of the remote form do most of the work:

  • The colon is the switch. web01:report.pdf means "the file report.pdf on the machine web01." Without the colon, web01 would just be a local filename — a distinction behind the most classic scp mistake, covered below.
  • Relative remote paths start at the login user's home directory. web01:report.pdf means ~/report.pdf on the far side; web01:/var/www/report.pdf is absolute. A bare trailing colon — scp file web01: — means "drop it in my home directory," which is the shortest useful destination there is.
  • user@ is optional. Omit it and scp uses your local username, or whatever your SSH configuration says for that host. In fact, scp reads your ~/.ssh/config exactly as ssh does — aliases, keys, ports, jump hosts, everything — which is why five minutes in SSH config as a transfer accelerator shortens every command on this page.

One ordering rule: flags go before the paths. scp stops looking for options once it hits the first path argument, so scp file web01: -P 2222 does not set the port — it looks for a file named -P. Write flags first, sources next, destination last, every time, and the parser will never surprise you.

While a copy runs, scp prints a progress meter worth being able to read at a glance: the filename, the percentage done, the bytes transferred so far, the current transfer rate, and an estimated time remaining. The rate column is the useful one — it tells you within seconds whether you are getting LAN speed or trickling through a saturated VPN, and a rate that collapses to zero with a climbing "stalled" counter means the connection is gone even though the command has not given up yet.

The Flags Worth Knowing

scp has a small option surface, and this table is nearly all of it. Everything else you will ever pass rides through -o as a standard SSH option.

Flag What it does Watch out
-r Recursive: copy a directory and everything in it Follows symlinks instead of copying them; no exclude filters
-p Preserve modification times and permission bits Lowercase. Not the port flag — see -P
-P Connect to a nonstandard SSH port Capital — the opposite of ssh, which uses -p
-i Use a specific private key (identity file) Agent keys may still be tried first; config can pin this per host
-C Compress data in transit Helps text on slow links; wastes CPU on fast LANs and compressed files
-l Limit bandwidth, in kilobits per second Kilobits: -l 8000 is roughly 1 MB/s
-3 Route remote-to-remote copies through your machine Data crosses your link twice; without it, host A must reach host B
-J Connect via a jump host (ProxyJump) Bastion must allow forwarding; older builds use -o ProxyJump=
-v / -q Verbose debugging / fully quiet output -v is your first move on any failure; -q suits cron logs
-o Pass any SSH client option by name The escape hatch: timeouts, key policies, anything ssh_config accepts

A Dozen Worked One-Liners

Each example below is a real task, stated the way it lands in your ticket queue. Adjust names and paths; the shapes are the lesson. The flags stack the way you would hope — scp -rpC -P 2222 is a perfectly legal opening — so treat these as ingredients, not fixed recipes.

Everyday copies

1. Push one file to a server's home directory. The bare colon means "my home directory over there" — fastest destination to type:

scp deploy-notes.txt alex@web01:

2. Pull a log file into your current directory. The lone dot is your local "right here":

scp alex@web01:/var/log/nginx/error.log .

3. Rename while copying. Give the destination a filename instead of a directory — useful for versioned config staging:

scp app.conf alex@web01:/etc/app/app.conf.new

4. Copy a whole directory tree. -r recurses; note that if /var/www/site already exists, this creates /var/www/site/site — the nesting surprise explained in the mistakes section:

scp -r site/ alex@web01:/var/www/site

5. Preserve timestamps and modes. Without -p, every file arrives stamped "now," which confuses build tools and any human comparing dates:

scp -rp build/ alex@web01:/opt/app/releases/build-candidate

Connection control

6. A server on a nonstandard SSH port. Capital -P, and it must come before the paths:

scp -P 2222 dump.sql alex@db01:/tmp/

7. Authenticate with a specific key. Deployment and service accounts usually have dedicated keys:

scp -i ~/.ssh/deploy_key artifact.tgz deploy@web01:/opt/releases/

8. Copy through a bastion in one command. -J tunnels the connection through the jump host end to end — nothing lands on the bastion. The full pattern, including why this beats agent forwarding, is in copying through bastions:

scp -J alex@bastion.example.com report.pdf alex@app01.internal:/srv/reports/

9. Set a timeout so scripts fail fast. Any SSH option rides along via -o; without this, a dead host can hang a script for minutes:

scp -o ConnectTimeout=5 -q nightly.csv alex@reports01:/incoming/

Power moves

10. Fetch every file matching a pattern. Single quotes keep your local shell's hands off the star so it is expanded on (or for) the remote side:

scp 'alex@web01:/var/log/app/*.log' ./logs/

11. Server-to-server through your machine. -3 means both sides authenticate as you, and host A never needs credentials for host B — the reachability story is diagrammed in SCP's limitations:

scp -3 alex@old-web:/etc/app/app.conf alex@new-web:/etc/app/

12. Cap the bandwidth on a shared link. The number is kilobits per second — here about 500 KB/s, slow enough to leave the office VPN breathing room during business hours:

scp -l 4000 backup.tgz alex@offsite:/archive/

13. Squeeze a text file over a slow WAN. Compression shines on logs, dumps, and CSVs across thin links — and does nothing useful for already-compressed archives:

scp -C giant-query-export.csv alex@analytics:/staging/

14. Debug a failing copy. Verbose output shows each authentication attempt and the exact failure point — read it before changing anything:

scp -v canary.txt alex@web01:/tmp/

One honorable mention that is not an scp command at all. When the job is thousands of small files, scp's per-file ceremony makes the copy crawl, and the veteran move is to stream a tar archive through ssh instead — one continuous pipe, no per-file overhead, attributes preserved. We work that pattern in full, jump hosts included, in copying through bastions; keep it in your pocket for the day a -r copy of a source tree seems to take geological time.

Reading -v output: if the log shows authentication succeeding and the failure arriving afterward, stop debugging SSH — the problem is the path, permissions, or disk on the far side. If it never gets past authentication, the problem is keys, agent, or account, and no path fix will help. That one split sorts most scp failures in seconds.

Passwords, Keys, and Prompts

Nothing about authentication is unique to scp — it authenticates exactly as ssh does — but a few consequences matter more for copying than for logging in.

First, every scp invocation is a fresh connection, and with password authentication that means a fresh password prompt. Run scp five times in a loop and you will type your password five times. The civilized fix is SSH key authentication: generate a key pair with ssh-keygen, install the public half on the server with ssh-copy-id, and every subsequent scp goes straight through. Add an agent (the small background process that holds your unlocked keys) and even a passphrase-protected key stops prompting. For genuinely repeated copies in one working session, connection multiplexing removes the per-command handshake as well — that trick lives in the SSH config article.

Second, prompts are fatal to unattended scripts. An scp inside cron that unexpectedly hits a password prompt, a first-contact host key question, or a passphrase request does not fail — it hangs, forever, with nobody watching. Two habits prevent that. Use key authentication for anything scheduled, and pass -o BatchMode=yes in scripts so that any situation which would require a human answer becomes an immediate, loggable error instead of a silent hang:

scp -o BatchMode=yes -o ConnectTimeout=5 -q result.csv alex@reports01:/incoming/ \
  || echo "upload failed" | mail -s "nightly copy failed" ops@example.com

Third, the host key question deserves respect. The first connection to a new server asks you to confirm its fingerprint; scripts should never blindly answer yes. Connect once interactively (or pre-load the fingerprint into known_hosts) before an automated job first runs, so automation only ever talks to hosts it already trusts.

The Mistakes Everyone Makes Once

Every item here is a rite of passage. Read the list now and skip the rite.

  • Lowercase -p when you meant -P. ssh takes -p for port, scp takes -P — a historical accident everyone trips on. The failure is sneaky: scp -p 2222 file web01: does not error. It quietly treats 2222 as a filename to copy and "preserve times" as the option, then complains that 2222 does not exist — or worse, copies a file actually named that.
  • Forgetting the colon. scp report.pdf web01 transfers nothing anywhere. It copies report.pdf to a new local file named web01, exits successfully, and lets you discover the truth later. Any time scp finishes suspiciously fast, look for a fresh local file named after your server.
  • Unquoted wildcards on remote paths. scp web01:/logs/*.log . lets your local shell try to expand the star first. Depending on your shell's settings you get "no match" errors or silent weirdness. Single-quote every remote glob, every time.
  • The recursive nesting surprise. scp -r site web01:/var/www/site creates /var/www/site/site if the target directory already exists, and /var/www/site if it does not — the same command, two different results depending on far-side state. When exact placement matters, copy into the parent (scp -r site web01:/var/www/). Note this differs from rsync's famous trailing-slash rules — our rsync series covers those.
  • Expecting a "file exists" warning. scp overwrites destination files silently. There is no interactive mode, no clobber protection. If the destination might hold something precious, look first or copy to a new name.
  • Trusting it with a huge file on a flaky link. No resume: an interruption at 97 percent means starting over. Size-times-fragility decisions belong to rsync or sftp, as argued in SCP's limitations.
  • Expecting ownership to travel. Files arrive owned by the account you logged in as, not by their original owner — copy a tree of files owned by a service account and they all land owned by you. Setting ownership on arrival requires privilege on the receiving side; plan a follow-up chown or use a transfer method that carries ownership deliberately.
  • Backgrounding a copy that still needs a password. Push an scp into the background or a detached session before authentication finishes and it sits suspended, waiting for a prompt nobody can see. Authenticate first (or use keys), then background the transfer.

scp on Windows

Current Windows systems include the OpenSSH client tools — ssh, scp, and sftp — ready to run from PowerShell or the command prompt, so every one-liner above works from a Windows admin workstation unchanged, keys and ~/.ssh/config included (the config lives under your user profile's .ssh folder, same syntax). Two local quirks worth knowing: quote Windows paths that contain spaces just as you would any other argument, and if a drive-letter path ever confuses scp (the colon in C: can resemble the remote-host separator in some environments), the painless fix is to cd into the folder and use relative paths — scp report.pdf web01: works identically from any operating system's prompt.

Receiving files on a Windows machine is a separate question, because scp and sftp need an SSH-based service listening on the far side. Windows offers an optional OpenSSH server for that. Where transfers are a first-class duty rather than an occasional convenience — partner uploads, scheduled feeds, audited access — a dedicated server product such as Sysax Multi Server gives the same Windows machine an SFTP (SSH2) endpoint with per-user accounts, access control, and activity logging managed from a GUI, alongside FTPS and HTTPS for clients that need them.

From One-Liners to Habits

Mastery of scp is not knowing forty flags — it is knowing these ten so well that the command disappears and only the task remains. When you can type any example on this page without looking, you are done; there is genuinely nothing more the tool is hiding.

Three follow-ups turn this page from a cheat sheet into a skill set. First, push the repetitive parts — usernames, ports, keys, jump hosts — into your SSH configuration so the one-liners shrink to scp file web01:; that is the whole subject of SSH config as a transfer accelerator. Second, internalize what no flag will fix — resume, remote management, delta transfer — and the tools that pick up where scp stops, mapped task by task in choosing your copy tool.

Third, notice the moment a one-liner stops being ad hoc. The command you now run every morning, the copy a colleague must remember to do on your vacation, the transfer a downstream system silently depends on — those have outgrown the terminal. On Windows, that is the job Sysax FTP Automation exists for: the same transfer defined once as a scheduled task over SFTP, FTPS, or FTP, with retries, error handling, and folder monitoring instead of a human with muscle memory.

Frequently Asked Questions

How do I copy an entire folder with scp?
Add -r for recursive: scp -r myfolder user@host:/target/. Copy into the parent directory of where you want the folder to land, because copying onto an existing directory of the same name nests a second copy inside it.
How do I use scp with a different SSH port?
Use a capital -P before the paths: scp -P 2222 file user@host:/tmp/. It is the opposite of ssh's lowercase -p, and lowercase -p in scp means "preserve timestamps" — a mix-up that fails quietly rather than loudly.
How do I tell scp which private key to use?
Pass -i with the key path: scp -i ~/.ssh/deploy_key file user@host:/dir/. If you use the same key for that host regularly, set IdentityFile for it in ~/.ssh/config once and drop the flag forever.
Why does my scp wildcard say "No such file or directory"?
Your local shell tried to expand the wildcard against your local disk before scp ran. Wrap the whole remote argument in single quotes — scp 'host:/path/*.log' . — so the pattern is expanded for the remote side instead.
Will scp warn me before overwriting a file?
No. scp overwrites the destination silently, with no interactive prompt or backup option. If the target might contain something you care about, check first with ssh and ls, or copy to a new name and rename afterward.
Can scp copy directly between two remote servers?
Yes — give two remote paths. By default the first host connects straight to the second, which requires network reachability and credentials between them; adding -3 routes the data through your own machine using only your credentials, at the cost of transferring twice over your link.

From the Sysax team: we build secure file transfer software for Windows — Sysax Multi Server, an FTP, FTPS, SFTP, and HTTPS server, and Sysax FTP Automation for scheduled, scripted transfers. Free trials are on the download page.