FTP Explained: How File Transfer Protocol Works

By | July 2, 2026

FTP is the oldest protocol you will still find running in a substation. It moves files between two machines over TCP. That is the whole job. But the way it does the job — two separate connections, plain-text commands, a server that calls you back — trips up more engineers than any other legacy protocol.

This article walks through FTP the way the specification defines it: the two-connection model, active and passive mode, transfer types, the command set, and the reply codes. Then we get practical: why FTP breaks through firewalls, why it fails security audits, and where it still earns its keep in industrial networks.

The Core Idea: Two Connections, Not One

Most protocols use one TCP connection. FTP uses two, and they do different work.

The control connection carries commands and replies. Your client opens it to TCP port 21 on the server. It stays open for the whole session. Everything you type — login, directory changes, transfer requests — travels here as plain readable text.

The data connection carries the actual file. It opens only when a transfer starts and it usually closes when the transfer ends. Directory listings travel here too, not on the control connection.

The specification splits each side into two roles. The protocol interpreter (PI) handles commands and replies on the control connection. The data transfer process (DTP) handles the data connection. So a full session involves four moving parts: user-PI, server-PI, user-DTP, server-DTP.

Why does this matter in practice? Because the control connection must stay open while data moves. If a firewall or NAT device times out the idle control connection during a long transfer, the server may kill the transfer. That is one of the two classic FTP firewall failures. The other one is bigger, and it comes down to who opens the data connection.

Active vs Passive Mode: Who Calls Whom

This is the part that causes 90% of real-world FTP problems.

Active mode (the original design)

In the original model, the client tells the server where to connect using the PORT command:

PORT 192,168,1,50,195,80

The first four numbers are the client’s IP address. The last two encode the TCP port: 195 × 256 + 80 = 49,920. The client listens on that port. The server then opens the data connection to the client, from its own port 20 (the port next to 21).

Think about that from a firewall’s point of view. An outside machine is opening an inbound connection to a random high port on your internal host. Every stateless firewall blocks it. Every NAT device breaks it, because the client advertises its private IP inside the PORT command payload.

Passive mode (the fix)

The client sends PASV instead. The server picks a port, listens on it, and replies:

227 Entering Passive Mode (10,20,30,40,156,68)

Now the client opens the data connection outbound, to server port 156 × 256 + 68 = 40,004. Outbound connections pass through client-side firewalls without trouble. That is why nearly every modern client defaults to passive mode.

The trade-off moves the problem to the server side: the server firewall must allow inbound connections on a range of high ports. Server admins handle this by pinning the passive port range in the FTP server config and opening exactly that range.

Third-party transfers

The two-connection design allows one thing no modern protocol does cleanly: a client can sit at host C and move a file directly between servers A and B. The client sends PASV to server A, takes the address from the 227 reply, and hands it to server B in a PORT command. Then it sends STOR to one server and RETR to the other. Data flows A-to-B without touching C. This is called FXP today. Most servers disable it because it is also an attack vector (the “FTP bounce” attack).

Transfer Types: ASCII vs Binary

FTP was written for a world where machines disagreed about what a byte was. Some hosts stored text as 7-bit ASCII packed into 36-bit words. Others used EBCDIC. The protocol defines four representation types, set with the TYPE command:

TypeCodeWhat it does
ASCIITYPE AConverts text to a standard network form. Line endings become CR+LF on the wire. This is the default.
EBCDICTYPE ESame idea, for EBCDIC mainframes. Dead in practice.
ImageTYPE IRaw bits, no conversion. What everyone calls “binary mode.”
LocalTYPE L nCustom logical byte size. Dead in practice.

The only decision that matters today: A or I.

ASCII mode rewrites line endings. Send a firmware image, a relay settings file, or a COMTRADE .dat file in ASCII mode and the transfer will “succeed” — with a corrupted file. Every 0x0A byte in the binary gets a 0x0D stuffed in front of it. The file size changes. Checksums fail. Firmware loads brick devices.

Rule of thumb: type binary (or TYPE I) before any transfer unless you know the file is plain text and you actually want line-ending conversion. Most modern clients auto-detect, but embedded FTP clients in RTUs and protection relays often do not.

Structures and Modes: The Parts Nobody Uses

The specification defines three file structures (STRU) and three transmission modes (MODE). You should know they exist, because you will see the commands in packet captures, and because the defaults explain some FTP behavior.

Structure: File (F), Record (R), or Page (P). File structure — a plain stream of bytes — is the default and the only one in real use. Record structure existed for mainframes that stored files as fixed records. Page structure existed for TOPS-20 “holey” files. If you see STRU F in a capture, the client is just confirming the default.

Mode: Stream (S), Block (B), or Compressed (C). Stream is the default and the only one in real use. Here is the interesting part: in stream mode with file structure, the only way to signal end-of-file is to close the data connection. That is why FTP opens a fresh data connection for every single transfer. Block mode wrapped data in headers with byte counts and supported restart markers for resuming failed transfers, so it could keep the connection open — but almost nobody implemented it. Modern clients resume transfers a different way, using the REST command with a byte offset plus stream mode.

The Command Set

FTP commands are short plain-text strings, four letters or fewer, terminated by CR+LF. Case does not matter: RETR, retr, and ReTr are the same command. Here are the ones that do the work:

Session and login

  • USER — username
  • PASS — password, sent in clear text
  • ACCT — account, rarely required
  • QUIT — log out and close
  • REIN — reset the session without closing the connection

Transfer setup

  • PORT — active mode: here is my address, connect to me
  • PASV — passive mode: give me an address, I will connect to you
  • TYPE — ASCII or Image
  • MODE, STRU — practically always at defaults

File operations

  • RETR — download a file
  • STOR — upload a file, overwriting if it exists
  • STOU — upload with a server-generated unique name
  • APPE — upload and append
  • DELE — delete a file
  • RNFR + RNTO — rename, always as a pair
  • REST — restart a transfer at a byte offset
  • ABOR — abort the transfer in progress

Directories

  • CWD — change directory
  • CDUP — go up one level
  • PWD — print the current directory
  • MKD / RMD — make or remove a directory
  • LIST — full listing, human-readable, format varies by server
  • NLST — names only, one per line, meant for scripts

Information

  • SYST — what OS is the server running
  • STAT — status of the server or a transfer
  • HELP, NOOP, SITE — help text, keep-alive, and server-specific extras

One detail worth knowing: LIST output is not standardized. A UNIX server sends something like ls -l output; other systems send whatever they like. Scripts that parse LIST break when the server changes. NLST exists precisely so automated tools get clean, parseable file names.

Reading Reply Codes

Every command gets at least one numeric reply. The three digits are a small state machine, and once you learn the pattern you can read any FTP session log without a reference.

First digit — how did it go:

  • 1yz — started, wait for another reply before sending a new command
  • 2yz — done, success
  • 3yz — accepted, but send the next command in the sequence (e.g. 331 after USER means “now send PASS”)
  • 4yz — failed, temporary; retrying the same command may work
  • 5yz — failed, permanent; retrying the same command will not help

Second digit — what area: 0 syntax, 1 information, 2 connections, 3 authentication, 5 file system.

The replies you will actually see:

CodeMeaning
220Service ready — the server greeting
331Username OK, need password
230Logged in
530Not logged in / bad credentials
227Entering passive mode (address follows)
150Opening data connection, transfer starting
226Transfer complete, closing data connection
425Can’t open data connection — usually a firewall problem
426Connection closed, transfer aborted
550File not found or permission denied
421Service not available, shutting down

A clean download reads like this on the control connection:

220 Service ready
USER field_eng          → 331 User name okay, need password
PASS ********           → 230 User logged in
TYPE I                  → 200 Command okay
PASV                    → 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2)
RETR dr_20260615.cfg    → 150 File status okay
                        → 226 Closing data connection
QUIT                    → 221 Service closing control connection

Multi-line replies start with the code and a hyphen (214-Help follows) and end with the same code and a space. Your parser looks for the second occurrence of the code at the start of a line.

The Minimum Implementation

The specification defines a floor every server must meet: TYPE ASCII Non-print, MODE Stream, STRUcture File and Record, and the commands USER, QUIT, PORT, TYPE, MODE, STRU, RETR, STOR, and NOOP. Anything beyond that — including PASV, LIST, and even PASS — is technically optional.

This matters for embedded devices. The FTP server baked into an older RTU, protection relay, or power quality meter often implements little more than this minimum. If your transfer script assumes MKD, MDTM, or SIZE exists, test against the actual device first. Some embedded stacks do not even support passive mode, which forces you back into active-mode firewall rules.

Why FTP Fails Security Audits

FTP predates the idea of a hostile network. Four problems, all structural:

1. Credentials in clear text. USER and PASS cross the wire readable. Anyone with a tap or a SPAN port capture has your password. On a flat OT network, that can be the same password used on twenty other devices.

2. Data in clear text. File contents are readable in transit. Settings files, configurations, event records — all of it.

3. No integrity checking. FTP relies on TCP for bit-level correctness and offers nothing above it. No hash, no signature. You cannot prove the file that arrived is the file that was sent.

4. The bounce attack. The PORT command lets a client tell a server to open a connection to any IP and port. An attacker uses your FTP server as a relay to scan or reach hosts behind it. Modern servers refuse PORT commands pointing at third-party addresses, but embedded stacks may not.

Add the firewall pain: an application-layer gateway must parse the control connection to learn which data ports to open, and that breaks the moment you encrypt the control channel.

FTP vs FTPS vs SFTP

Three names, two protocols, one common confusion.

FTPS is FTP wrapped in TLS. Same commands, same two-connection model, now encrypted. Explicit FTPS starts plain on port 21 and upgrades with an AUTH TLS command. Implicit FTPS uses port 990 and is TLS from the first byte. FTPS fixes the eavesdropping problem but keeps the two-connection firewall problem — and makes it worse, because the firewall can no longer read the PASV replies to open data ports dynamically.

SFTP is not FTP at all. It is a file transfer subsystem running inside an SSH session. One connection, one port (22), encrypted, with integrity built in. From a firewall’s point of view it is the simplest of the three by a wide margin.

Practical guidance: for new deployments, use SFTP. Use FTPS when a counterparty or a legacy toolchain demands the FTP command set with encryption. Use plain FTP only inside a controlled network segment where the risk is understood and documented — which brings us to OT.

Where FTP Still Lives in Industrial Networks

Plenty of field devices shipped with FTP and nothing else. You will meet it when:

  • Pulling disturbance records — protection relays exposing COMTRADE files over an embedded FTP server
  • Firmware updates — RTUs and gateways that only accept firmware via FTP push
  • Retrieving logs and configurations — meters, PQ analyzers, older HMIs and station computers
  • Automated collection — a station computer polling devices on a schedule and forwarding files up to the control center

You often cannot replace the device, so you contain the protocol instead:

  1. Keep FTP inside one network zone. Never let it cross a zone boundary unencrypted — put a secured relay point (SFTP gateway or data diode arrangement) at the conduit.
  2. Use unique credentials per device, even though they travel in the clear. Shared passwords turn one capture into total compromise.
  3. Pin the passive port range on any server you control and firewall exactly that range.
  4. Force binary mode in every script. An ASCII-mode firmware transfer is a bad day.
  5. Log the control connection. It is plain text — that is a weakness for confidentiality but a gift for monitoring. Every command and reply is auditable.

Quick Reference

  • Control connection: TCP port 21, stays open all session
  • Data connection: port 20 in active mode, negotiated high port in passive mode
  • Default settings: TYPE ASCII, MODE Stream, STRU File
  • Switch to binary with TYPE I before any non-text transfer
  • 2xx replies mean success, 4xx retry later, 5xx don’t bother
  • 425 almost always means a firewall is blocking the data connection
  • FTPS = FTP over TLS; SFTP = a different protocol over SSH

FAQ

What port does FTP use?

Port 21 for the control connection. In active mode the server sends data from port 20. In passive mode the server assigns a high port for each transfer and tells the client in the 227 reply.

What is the difference between active and passive FTP?

In active mode the server opens the data connection to the client. In passive mode the client opens the data connection to the server. Passive mode is the default in modern clients because client-side firewalls block inbound connections.

Why did my FTP transfer corrupt the file?

Almost certainly ASCII mode. The default transfer type converts line endings, which rewrites bytes inside binary files. Send TYPE I (binary) before transferring firmware, images, archives, or measurement data.

Is FTP secure?

No. Usernames, passwords, and file contents all travel as readable text, and the protocol has no integrity checking. Use SFTP or FTPS on any network you do not fully control.

What is the difference between SFTP and FTPS?

FTPS is classic FTP with TLS encryption added — same commands, same two connections. SFTP is a separate protocol that runs over SSH on port 22 with a single connection. They are not interoperable.

Why does my firewall block FTP?

FTP negotiates a second connection on a dynamic port, and the address is carried inside the protocol payload. Stateless firewalls and NAT devices can’t track it. Fixes: use passive mode, enable FTP inspection on the firewall, or pin the server’s passive port range and open it explicitly.

What does reply code 550 mean?

Permanent failure at the file level: the file does not exist, or you lack permission. Check the path, the case of the file name, and your account’s access rights.

Can FTP resume a broken transfer?

Yes, if the server supports REST. The client sends REST <byte offset> followed by RETR or STOR, and the transfer continues from that point.

Author: Zakaria El Intissar

I've spent 13 years in power system automation, electrical protection, and SCADA communication, as an automation and industrial computing engineer. ScadaProtocols.com is where I turn what I've learned on site into plain guides and working tools — so other engineers can decode, analyze, and troubleshoot industrial communication protocols without the guesswork.