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
| Protocol | Port | Role | Encrypted |
|---|---|---|---|
| FTP control | 21/tcp | Login and commands, client to server | No |
| FTP data, active mode | 20/tcp | Server connects from port 20 back to a port the client named | No |
| FTP data, passive mode | a range you set, e.g. 40000-40100/tcp | Client connects to a port the server named | No |
| FTPS, explicit | 21/tcp + the passive range | Starts plain, AUTH TLS upgrades the connection | Yes, TLS |
| FTPS, implicit | 990/tcp + the passive range | TLS from the first byte | Yes, TLS |
| SFTP | 22/tcp | One SSH connection carries everything | Yes, SSH |
| TFTP | 69/udp | No login; network boot and device configs | No |
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(orEPRT) 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(orEPSV), 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.
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 tooFileZilla, 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.
# 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:
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/uploadAdd this block at the very end of /etc/ssh/sshd_config:
Match Group sftponly
ChrootDirectory %h
ForceCommand internal-sftp
AllowTcpForwarding no
X11Forwarding nosudo sshd -t && sudo systemctl restart sshsshd -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.
sudo apt update
sudo apt install -y vsftpd ssl-cert
sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.origThe 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:
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.10With 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:
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 sshOpen the ports, restart, and test from your own computer:
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/< 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
| Symptom | Likely cause | Check or fix |
|---|---|---|
| Connection timed out before login | Port 21 filtered, or the wrong IP | nc -zv 203.0.113.10 21, then the server firewall |
| Connection refused | Nothing listens on 21 | sudo systemctl status vsftpd, sudo ss -ltnp |
| Login works, listing times out | Passive range closed or not configured | Open pasv_min_port to pasv_max_port in the firewall |
| Server sent passive reply with unroutable address | Server advertises a private IP | Set pasv_address to the public IP (NAT only) |
425 Failed to establish connection. | The data connection failed | Passive range, or active mode from behind NAT |
530 Login incorrect. | Wrong password, user listed in /etc/ftpusers (root is), or shell missing from /etc/shells | Check the password and both files |
530 Non-anonymous sessions must use encryption. | The client tried plain FTP | Choose Require explicit FTP over TLS |
500 OOPS: vsftpd: refusing to run with writable root inside chroot() | The user can write to its chroot directory | Root-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:
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 ftpsvcMicrosoft’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.