Guides

FTP port numbers: 21, 20, passive ranges, FTPS 990 and SFTP 22 explained

FTP uses port 21 for commands and port 20 or a passive range for data. FTPS adds TLS on 21 or 990, SFTP runs over SSH on 22. Which to open, and which to use.

Published ~11 min read

Short answer: FTP uses TCP port 21 for its control connection, where you log in and send commands. Every file transfer and directory listing opens a second, data connection: from server port 20 in active mode, or to a server port from a range you choose in passive mode. FTPS is FTP with TLS, either upgraded on port 21 (explicit) or encrypted from the start on port 990 (implicit). SFTP is a different protocol that runs over SSH on port 22.

On your own VPS, use SFTP: it is already there with SSH, it is encrypted, and it needs no port beyond the one you log in on. Run an FTP server only when a device or a program cannot do anything else, and then give it a fixed passive range and TLS, as shown below.

FTP ports at a glance

ProtocolPortRoleEncrypted
FTP control21/tcpLogin and commands, client to serverNo
FTP data, active mode20/tcpServer connects from port 20 back to a port the client namedNo
FTP data, passive modea range you set, e.g. 40000-40100/tcpClient connects to a port the server namedNo
FTPS, explicit21/tcp + the passive rangeStarts plain, AUTH TLS upgrades the connectionYes, TLS
FTPS, implicit990/tcp + the passive rangeTLS from the first byteYes, TLS
SFTP22/tcpOne SSH connection carries everythingYes, SSH
TFTP69/udpNo login; network boot and device configsNo

Two numbers cause confusion. IANA also registers 989 as “ftps-data”, but implicit FTPS servers normally hand out passive ports like plain FTP does. And port 115 is registered under the name “sftp”, which is the long-dead Simple File Transfer Protocol, not the SFTP you use with SSH.

The ports of everything else a server runs, from SSH and mail to databases, are in the common ports reference.

Why port 21 alone is not enough

FTP keeps commands and data apart. Port 21 carries the login, CWD, DELE and the other commands. Every directory listing, upload and download opens a separate data connection on another port, and closes it afterwards. So an FTP server with only port 21 open shows a typical pattern: the login succeeds, and then the directory listing hangs until the client gives up. That is almost never a password or permission problem. The data port is blocked.

Active vs passive mode

  • Active mode: the client opens a port on its side and sends PORT (or EPRT) with its address. The server connects back to it, from port 20. That usually fails when the client sits behind NAT or a firewall, which is where nearly every client sits today.
  • Passive mode: the client sends PASV (or EPSV), the server opens a port and replies with its number, and the client connects to it. Only the server’s firewall has to allow the range.
FTP session · passive replies
PASV
227 Entering Passive Mode (203,0,113,10,156,64)
# address 203.0.113.10, port 156 × 256 + 64 = 40000

EPSV
229 Entering Extended Passive Mode (|||40000|)
# extended form: port only, works for IPv6 too

FileZilla, WinSCP and curl use passive mode by default; curl tries EPSV first and falls back to PASV. The ftp.exe built into Windows only does active mode, as Microsoft’s own IIS documentation notes, so do not use it to test a server across the internet. Browsers are out too: Chrome removed FTP in version 88 and Firefox in version 90.

FTPS: explicit TLS on 21, implicit TLS on 990

Explicit FTPS connects to port 21 as usual, and the client sends AUTH TLS to switch the control connection to TLS before logging in. RFC 4217 standardises this, and it is what current servers and clients expect. Implicit FTPS starts the TLS handshake immediately on port 990, with no plain-text phase. It is the older variant, and curl’s documentation recommends the explicit way. Both still need the passive range for data.

Encryption removes a crutch plain FTP leans on. Many routers and firewalls read the 227 reply on port 21 and quietly fix the address or open the port. With TLS they cannot read it, so the server has to advertise the right public address and use a range that is open. That is why FTPS often fails on a setup where plain FTP seemed to work.

from your computer · test FTPS
# explicit FTPS: is TLS offered on 21, and with which certificate?
openssl s_client -connect 203.0.113.10:21 -starttls ftp

# implicit FTPS on 990
openssl s_client -connect 203.0.113.10:990

# log in and list, and refuse to fall back to plain FTP
curl -v --ssl-reqd -u alice ftp://203.0.113.10/

In FileZilla, pick Require explicit FTP over TLS (or Require implicit FTP over TLS for port 990) under Encryption in the Site Manager. The setting “Use explicit FTP over TLS if available” falls back to plain FTP when the server does not offer TLS, and “Only use plain FTP” sends your password in clear text.

SFTP: file transfer over SSH on port 22

SFTP has nothing in common with FTP except the purpose. It is a subsystem of SSH: one encrypted connection on the SSH port, the same users, passwords and keys, and nothing else to open. Every Linux server with OpenSSH already offers it. If you moved SSH to another port, SFTP moves with it, so connect with sftp -P 2222 user@203.0.113.10 or enter that port in the client; the SSH port guide shows how to find out which one it is. The scp command takes the same -P. Transferring files to a VPS covers WinSCP, FileZilla and rsync.

An SFTP-only account for uploads

For a colleague, a script or a CMS that should upload files but never get a shell, lock an account to SFTP inside its own directory:

Debian · Ubuntu
sudo groupadd sftponly
sudo useradd -d /srv/sftp/webupload -s /usr/sbin/nologin -G sftponly webupload
sudo passwd webupload
sudo mkdir -p /srv/sftp/webupload/upload
sudo chown root:root /srv/sftp /srv/sftp/webupload
sudo chmod 755 /srv/sftp /srv/sftp/webupload
sudo chown webupload:webupload /srv/sftp/webupload/upload

Add this block at the very end of /etc/ssh/sshd_config:

/etc/ssh/sshd_config
Match Group sftponly
    ChrootDirectory %h
    ForceCommand internal-sftp
    AllowTcpForwarding no
    X11Forwarding no
Debian · Ubuntu
sudo sshd -t && sudo systemctl restart ssh

sshd -t checks the syntax first, and your current session survives the restart; test the new account from a second window before you close it. sshd only accepts a chroot whose every directory is owned by root and writable by nobody else, which is why the home directory belongs to root and the user writes into upload/. For key logins, put the key in /srv/sftp/webupload/.ssh/authorized_keys, owned by webupload, with the directory at mode 700 and the file at 600.

If you need FTP: vsftpd with a fixed passive range

Some things only speak FTP: IP cameras, scanners, old deploy plugins. For those, run vsftpd with TLS required and a passive range you control.

Debian · Ubuntu
sudo apt update
sudo apt install -y vsftpd ssl-cert
sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.orig

The packaged config already disables anonymous logins, allows local users and serves IPv4 and IPv6 through one socket (listen_ipv6=YES). In /etc/vsftpd.conf, uncomment write_enable, local_umask and chroot_local_user, change the existing ssl_enable=NO to YES, and add the passive settings, so the relevant lines read:

/etc/vsftpd.conf
write_enable=YES
local_umask=022
chroot_local_user=YES
ssl_enable=YES
force_local_logins_ssl=YES
force_local_data_ssl=YES
pasv_enable=YES
pasv_min_port=40000
pasv_max_port=40100
# only if the server sits behind NAT and does not own its public IP:
#pasv_address=203.0.113.10

With ssl_enable=YES, vsftpd uses the self-signed “snakeoil” certificate the file already points to, and clients ask you to trust it once. For a trusted certificate, point rsa_cert_file and rsa_private_key_file at a Let’s Encrypt fullchain.pem and privkey.pem. A hundred passive ports is plenty for a few clients; every listing and transfer takes one for a moment.

Now an account. vsftpd refuses to chroot a user into a directory that user can write to, so use the same layout as for SFTP. On Debian and Ubuntu, vsftpd’s PAM rules also reject users whose shell is not listed in /etc/shells, which is the case for nologin:

Debian · Ubuntu
sudo useradd -d /srv/ftp-users/camera -s /usr/sbin/nologin camera
sudo passwd camera
sudo mkdir -p /srv/ftp-users/camera/upload
sudo chown root:root /srv/ftp-users/camera
sudo chown camera:camera /srv/ftp-users/camera/upload
grep -qx /usr/sbin/nologin /etc/shells || echo /usr/sbin/nologin | sudo tee -a /etc/shells

# the account has a password, so keep it out of SSH
echo 'DenyUsers camera' | sudo tee /etc/ssh/sshd_config.d/90-ftp-users.conf
sudo sshd -t && sudo systemctl restart ssh

Open the ports, restart, and test from your own computer:

Debian · Ubuntu
sudo ufw allow 21/tcp
sudo ufw allow 40000:40100/tcp
sudo systemctl restart vsftpd
sudo ss -ltnp | grep vsftpd

# on your computer; -k accepts the self-signed certificate, for this test only
curl -v --ssl-reqd -k -u camera ftp://203.0.113.10/
Example output (FTP commands and replies only)
< 220 (vsFTPd 3.0.5)
> AUTH SSL
< 234 Proceed with negotiation.
> USER camera
< 331 Please specify the password.
< 230 Login successful.
> PBSZ 0
< 200 PBSZ set to 0.
> PROT P
< 200 PROT now Private.
> PWD
< 257 "/" is the current directory
> EPSV
< 229 Entering Extended Passive Mode (|||40023|)
> TYPE A
< 200 Switching to ASCII mode.
> LIST
< 150 Here comes the directory listing.
< 226 Directory send OK.

The TLS handshake lines, the password and the listing itself are left out above. AUTH SSL is curl’s first try at the upgrade, and vsftpd accepts it like AUTH TLS. PROT P means the data connection is encrypted too. The number in the 229 reply is the passive port, which has to fall between 40000 and 40100; the listing follows the 150. Debian 12 reports vsFTPd 3.0.3 in the first line, Debian 13 and Ubuntu 24.04 3.0.5. The ufw guide explains the rest of the firewall.

To test from outside without an FTP client, use the open port checker on your server’s IP. Port 21 should come back Open. A port inside the passive range should come back Closed, even though no transfer is running: the server answered that nothing listens there right now, so the firewall let the probe through. No answer means a firewall still drops the range.

FTP errors and the port behind them

SymptomLikely causeCheck or fix
Connection timed out before loginPort 21 filtered, or the wrong IPnc -zv 203.0.113.10 21, then the server firewall
Connection refusedNothing listens on 21sudo systemctl status vsftpd, sudo ss -ltnp
Login works, listing times outPassive range closed or not configuredOpen pasv_min_port to pasv_max_port in the firewall
Server sent passive reply with unroutable addressServer advertises a private IPSet pasv_address to the public IP (NAT only)
425 Failed to establish connection.The data connection failedPassive range, or active mode from behind NAT
530 Login incorrect.Wrong password, user listed in /etc/ftpusers (root is), or shell missing from /etc/shellsCheck the password and both files
530 Non-anonymous sessions must use encryption.The client tried plain FTPChoose Require explicit FTP over TLS
500 OOPS: vsftpd: refusing to run with writable root inside chroot()The user can write to its chroot directoryRoot-owned home with a writable subfolder

FTP on a Windows Server VPS

On Windows Server, SFTP is again the easier path. Windows Server 2025 has OpenSSH Server installed and only needs Remote SSH Access switched on under Local Server in Server Manager; on 2019 and 2022, add it with Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 and start the sshd service. The file transfer guide has the full steps, keys included. If you need the IIS FTP server, set the Data Channel Port Range under FTP Firewall Support at the server level in IIS Manager (valid ports are 1024 to 65535), and an external IP for the site only if the server is behind NAT. Restart the Microsoft FTP Service, then open the ports:

PowerShell (as administrator)
New-NetFirewallRule -DisplayName 'FTP control' -Direction Inbound -Protocol TCP -LocalPort 21 -Action Allow
New-NetFirewallRule -DisplayName 'FTP passive' -Direction Inbound -Protocol TCP -LocalPort '40000-40100' -Action Allow
netsh advfirewall set global StatefulFtp disable     # for FTPS, as Microsoft's IIS guide does
Restart-Service ftpsvc

Microsoft’s IIS documentation notes that the firewall’s stateful FTP filter cannot read encrypted FTPS traffic and switches it off for FTPS. With fixed port rules like these, nothing depends on that filter. The guide to opening a port in Windows Firewall covers the graphical way and scoping a rule to your own IP. A Windows VPS gives you the Administrator access all of this needs.

Which one should you use?

  • Your own VPS: SFTP on the SSH port. No extra ports, key logins, one connection.
  • A device or program that only speaks FTP: explicit FTPS on 21 with TLS required and a fixed passive range.
  • Implicit FTPS on 990: only when a client insists on it.
  • Plain FTP across the internet: not at all. The password crosses the network in clear text.
  • Domains behind Cloudflare: the proxy carries HTTP and HTTPS only, so connect to the IP or to a hostname set to DNS only.

Every VMHeaven KVM plan gives you full root on Linux, so SFTP works from your first SSH login. If all you need is a website, a Plesk hosting account shows its FTP and SFTP ports in the panel and can deploy from Git instead.

Frequently asked

Is SFTP just FTP on port 22?

No. SFTP is a file transfer subsystem of SSH, so it runs over a single encrypted SSH connection on whatever port sshd uses, 22 by default, with the same users and keys. FTP and FTPS are a different protocol that needs port 21 plus separate data connections.

Which ports do I need to open for passive FTP?

Port 21/tcp for the control connection and the passive range you configured on the server, for example 40000-40100/tcp in vsftpd with pasv_min_port and pasv_max_port. Port 20 only matters for active mode, where the server connects out to the client.

Does FTPS use port 21 or port 990?

Both exist. Explicit FTPS connects to port 21 and switches to TLS with the AUTH TLS command, which is what current servers and clients use. Implicit FTPS starts TLS immediately on port 990 and is the older variant. Either way, data still flows through the passive port range.

Related articles

All guides