The names suggest three versions of one thing. They are not. Two are related, one is entirely separate, and the one that sounds oldest is the one people still use by accident.
FTP: do not use it
FTP dates from 1971 and predates any expectation of a hostile network. Everything travels in plaintext - commands, file contents, and the username and password. Anyone positioned between client and server reads the credentials directly off the wire.
It also uses two connections: a control connection for commands, and a separate data connection for transfers. That second connection is negotiated dynamically, which is the source of FTP’s legendary awkwardness with firewalls and NAT, and the reason “active” and “passive” mode exist as concepts anyone has to learn.
There is no situation in 2026 where plain FTP is correct for anything crossing a network you do not physically control.
FTPS: FTP with TLS added
FTPS is FTP wrapped in TLS - the same encryption as HTTPS. Credentials and data are encrypted, which fixes the fatal flaw.
It inherits everything else. The two-connection design remains, so the firewall awkwardness remains, and now the data connection needs its own TLS negotiation too.
It also comes in two incompatible flavours:
Implicit FTPS assumes TLS from the first byte, conventionally on port 990.
Explicit FTPS (FTPES) connects normally on port 21 and issues AUTH TLS to
upgrade.
These are not interchangeable, and “FTPS doesn’t work” very often means the client and server disagree about which one they are speaking. Explicit is the modern default.
FTPS exists mainly so organisations can keep FTP-shaped tooling while satisfying an encryption requirement. That is a real need, and it is the main reason to choose it.
SFTP: not FTP at all
Despite the name, SFTP has no relationship to FTP. It is a subsystem of SSH, sharing its authentication, its encryption and its port.
The consequences are all favourable:
One connection, one port. Usually 22. Firewall configuration is trivial, and there is no active/passive distinction to debug.
Key-based authentication. SSH keys are both more secure than passwords and far easier to automate - no credential embedded in a script.
Universal availability. OpenSSH ships on every Linux distribution, on macOS, and on modern Windows. If a machine exists, it can almost certainly speak SFTP.
Real file operations. Resume, rename, permissions, directory listings with attributes.
Its one genuine weakness is throughput on very high-latency links: the protocol is more conversational than a raw stream, so a satellite link exposes it. In ordinary use this does not matter.
Choosing
Use SFTP unless something specific rules it out. One port, key authentication, universal support, no mode confusion.
Use FTPS when a system you do not control requires it. Some managed file transfer platforms and older enterprise integrations do, and that is a legitimate constraint rather than a preference.
Use FTP never, over any network you do not own end to end.
Where object storage fits instead
For anything scripted, the S3 API is frequently a better fit than any of the three. It brings multipart upload for large files, parallel range requests, presigned URLs, and an ecosystem of tooling - rclone being the obvious entry point.
A rough division:
| Client | Protocol |
|---|---|
| A person browsing in Finder or Explorer | WebDAV |
| A script, pipeline or backup job | S3 |
| A legacy system that expects a file server | SFTP |
| A partner’s managed transfer platform | Whatever they mandate |
Testing a connection quickly
Before wiring anything into a script, confirm the basics by hand.
SFTP, which is usually a one-liner:
sftp -P 22 user@host
Add -v if it fails - the verbose output names the authentication method that was
rejected, which is nearly always the answer.
FTPS with curl, useful because curl distinguishes the two flavours explicitly:
# Explicit FTPS (the modern default)
curl --ssl-reqd -u user ftp://host/
# Implicit FTPS
curl -u user ftps://host:990/
If explicit fails and implicit works, or vice versa, you have found the mode mismatch that causes most “FTPS doesn’t work” reports.
Checking what a host actually offers:
nc -vz host 22 # SFTP
nc -vz host 21 # FTP / explicit FTPS
nc -vz host 990 # implicit FTPS
An open port 21 on a server you administer is worth investigating even if you believe FTP is disabled - packages frequently enable a daemon on install.
Practical hardening
Whichever you land on, a few things pay for themselves immediately.
Prefer keys over passwords for anything automated. A key can be revoked individually and never gets typed into a phishing page.
Give each system its own credential. One per script, one per partner, one per machine. When something needs revoking - and eventually something will - you want to revoke exactly that thing without an outage everywhere else.
Scope credentials to a directory where the protocol supports it. A backup uploader does not need read access to everything.
Keep a record of what connected and when. During an incident, the question is always “what did this credential touch”, and the answer must already exist. Our guide on what a file audit log should record covers what makes a trail useful rather than merely present - the short version is that denied attempts matter more than successful ones.
Disable the protocols you are not using. An FTP daemon left running because it came with the package is a credential-harvesting opportunity nobody is watching.