FTPS explicit vs implicit: ports 21 and 990 explained
With FTPS, explicit vs implicit is only about how the session begins: both encrypt it the same way. Explicit FTPS connects to the normal FTP port, 21, in plain text, then asks the server to switch to TLS with the AUTH TLS command. Implicit FTPS starts TLS from the very first byte, conventionally on port 990, so there is no plain-text phase at all. Explicit is the standardised form (RFC 4217) and the one to prefer. Implicit is an older convention that some servers and partners still require.
Choosing the wrong one does not weaken security. It just fails to connect, often with an unhelpful timeout. Here is what each looks like on the wire, and how to tell which one a server expects.
Explicit FTPS, step by step
The client opens a TCP connection to port 21 and the server greets it in plain text, exactly as with ordinary FTP. The client then asks for TLS:
S: 220 FTP server ready
C: AUTH TLS
S: 234 Proceed with negotiation
(TLS handshake: certificate checked here)
C: USER deploy
S: 331 Password required
C: PASS ********
S: 230 Logged in
C: PBSZ 0
S: 200 PBSZ set to 0
C: PROT P
S: 200 Protection level set to Private
Everything after the 234 reply, including the username and password, is inside TLS. PBSZ 0 is a formality that RFC 4217 requires before PROT. PROT P is what encrypts the data connections that carry listings and file contents. Skip it and you get a protected password with your files crossing in the clear.
The catch with explicit mode
Because the session starts unencrypted, a server can be set up to allow TLS without requiring it, and someone tampering with the connection can strip the AUTH TLS exchange. A client set to FTPS must therefore treat a refused AUTH TLS or PROT P as a hard failure, never as a cue to carry on in plain FTP. On the server side, configure it to refuse logins that have not upgraded.
Implicit FTPS
With implicit FTPS the client starts a TLS handshake the moment the TCP connection opens. There is no AUTH command, because there is nothing to upgrade. The greeting, the login and every command after it happen inside TLS from the start. Port 990 is the conventional control port. Data connections are TLS from their first byte too, and clients still send PBSZ 0 and PROT P, which most servers expect.
Implicit mode is the older approach, dating from before RFC 4217 settled on the explicit upgrade, and it was never standardised in an RFC. It is still around because it is simple to firewall as "TLS on port 990" and some older systems were built around it.
FTPS explicit vs implicit at a glance
| Explicit FTPS | Implicit FTPS | |
|---|---|---|
| Control port | 21 (same as FTP) | 990 |
| Starts as | Plain text, upgraded with AUTH TLS | TLS from the first byte |
| Standard | RFC 4217 | Convention only |
| Same port can serve plain FTP | Yes | No |
| Encryption once running | TLS | TLS |
The data channel, in both modes
FTPS keeps FTP's separate data connections, so two more things decide whether transfers work:
- Passive ports. Firewalls cannot read the encrypted
PASVorEPSVreply to open the data port automatically, as they can with plain FTP. The server needs a fixed passive port range, opened on every firewall in between. - TLS session reuse. Many servers insist that each data connection resumes the TLS session of the control connection, to prove the same client opened both. vsftpd does this by default with
require_ssl_reuse. A client that does not reuse sessions sees the login succeed and then every listing fail.
Which should you use?
- If the server offers explicit FTPS, use it, with TLS required for login and data.
- Use implicit FTPS when a server or partner only offers port 990.
- If you have a choice of protocol altogether, SFTP avoids the data-channel and firewall issues entirely. SFTP vs FTP vs FTPS compares them.
How to tell which one a server speaks
OpenSSL can test both from Terminal. For explicit FTPS, it connects to port 21, sends AUTH TLS for you and prints the certificate:
openssl s_client -connect ftp.example.com:21 -starttls ftp
For implicit FTPS, connect straight to 990 with no -starttls:
openssl s_client -connect ftp.example.com:990
curl can then try a real login. ftp:// with --ssl-reqd means explicit and refuses to continue unencrypted, while ftps:// means implicit:
curl -v --ssl-reqd --user deploy ftp://ftp.example.com/
curl -v --user deploy ftps://ftp.example.com/
Symptoms of a mix-up
- Implicit settings against an explicit server on 21: the client sends a TLS ClientHello, the server replies with a plain-text
220greeting, and the handshake fails at once. - Explicit settings against port 990: the client waits for a greeting while the server waits for a TLS handshake. Nothing happens until a timeout.
- Login works, listings hang: almost always the passive port range or a firewall, not the FTPS mode.
Explicit and implicit FTPS in Wharf
Wharf lists both in the site editor's Protocol picker, as FTPS (explicit) and FTPS (implicit). Choosing one sets the port to 21 or 990; change it if your server uses something else.
In explicit mode Wharf sends AUTH TLS after the greeting and stops if the server refuses it. In both modes it then sends PBSZ 0 and PROT P, and stops if the server will not protect the data channel, so a session never falls back to unencrypted transfers. Data connections are passive (EPSV first, then PASV) and reuse the control connection's TLS session, which keeps servers that require session reuse happy.
Certificates are checked for validity and against the hostname. For a server you control that uses a self-signed certificate, Allow untrusted certificate under Advanced relaxes that for one site only; read FTPS and self-signed certificates before turning it on. The support page covers the same setting.
When something still does not connect, View › Server Log… (⌘⇧K) shows every command and reply, with passwords redacted, which usually makes the failing step obvious. More on Wharf's protocol support is in the features overview.