HomeTopicsThe FTP Protocol › Control & Data Channels

The Two-Channel Architecture: FTP's Control and Data Connections, Explained with a Packet Capture

Ask a room of administrators how many network connections an FTP session uses, and most will say one. That guess is wrong, and it is behind a remarkable share of FTP trouble tickets. Every FTP session is at least two separate TCP connections: one carries the conversation, one (or more) carries the goods. Firewalls, NAT devices, and troubleshooting admins all have to account for both, and anything that accounts for only one eventually breaks something.

This article takes the two-channel architecture apart properly. You will see what each connection actually carries (including one thing that surprises almost everyone), why the protocol was designed this way, and — the centerpiece — a full session walked through as it appears in a packet capture, line by annotated line. By the end, a raw session log will read like plain English.

This is the foundation article of our The FTP Protocol series. Everything else in the series — reply codes, failure modes, account models — builds on the mental picture we assemble here.

One FTP Session Is Two TCP Connections

A quick definition first: a TCP connection is the reliable, two-way byte stream most internet protocols are built on, identified by four numbers — source address and port, destination address and port. When we say FTP uses two connections, we mean two fully independent TCP streams, each with its own handshake, its own port pair, and its own lifetime.

The first is the control connection. Your FTP client opens it to the server — normally to port 21 — the moment you connect, and it stays open for the entire session. It carries only small lines of text: the commands your client sends and the numbered replies the server returns. Login, changing directories, requesting a file — all of it is negotiated here. What never travels on the control connection is the file itself.

The second is the data connection. This one carries the payload: the bytes of the file you upload or download, and — here is the surprise — the output of directory listings too. When your client shows you the contents of a folder, that listing arrived over a data connection, not the control connection. A data connection is temporary by design: a fresh one is negotiated for each transfer or listing, used exactly once, and closed.

An analogy that holds up well: think of a lumber yard. The front counter is the control connection — you stand there the whole visit, asking questions and placing orders. The loading dock is the data connection — every order comes out through the dock on its own forklift trip. Counter and dock are physically separate paths, and a problem at the dock does not stop you from talking at the counter.

The diagram below shows the shape of a real session: one long-lived control connection, plus a separate short-lived data connection for each listing or transfer the session performs.

FTP Client opens connections from ephemeral high ports FTP Server control: port 21 data: negotiated ports Control connection — open the whole session Data connection #1 — carries the directory listing, then closes Data connection #2 — carries the downloaded file, then closes Commands and replies never mix with file bytes: separate connections, separate ports.

Why Split Commands from Data at All?

Modern protocols mostly do the opposite — HTTP sends the request and the response body down the same connection — so FTP's split can look like needless complication. It was actually a deliberate design with real benefits, and knowing them makes the architecture feel less arbitrary.

  • The control channel stays responsive during transfers. Because commands do not queue up behind file bytes, a client can talk to the server in the middle of a long transfer — most usefully to send ABOR, the abort command, or to ask for status. With a single shared connection, a request to cancel a transfer would be stuck in line behind the very bytes it is trying to cancel.
  • End of file is dead simple. In FTP's normal stream mode, the sender signals "that was the whole file" by closing the data connection. No length headers, no chunk framing, no delimiters that might appear inside the file. A connection that exists for exactly one transfer can use its own closure as the end marker.
  • Each channel suits its traffic. The control connection carries tiny, bursty lines of text; the data connection carries sustained bulk streams. Separating them meant either could be handled, routed, or even relayed differently.
  • Third-party transfers were possible. A client could hold control connections to two servers and have one send a file directly to the other — the data connection ran between the servers, touching the client not at all. Most servers ship with this disabled today as an abuse vector, but it shows how thoroughly independent the two channels are.

The cost of the split arrived later, when firewalls and NAT changed the rules of the network. A firewall that permits port 21 has only permitted the conversation — the data connection is a second stream on a different port, and someone must open a path for it too. Which side opens it, and toward whom, is the entire subject of active versus passive mode — a story we leave to its own series, starting with active vs passive FTP explained. Here it is enough to know that the data connection's endpoints are negotiated fresh, over the control connection, before every transfer.

The Command Conversation on Port 21

The control connection speaks one of the friendliest wire formats in networking: plain, human-readable lines of text, each ending with a carriage return and line feed. A command is a short keyword, usually three or four letters, optionally followed by an argument. A reply is a three-digit number followed by explanatory text. That is the whole grammar. You could conduct an entire FTP session by hand over a raw TCP connection, typing commands yourself — and in the FTP lab article we do exactly that as an exercise.

One habit to build immediately: the words your client shows you are not the words on the wire. When you type ls in a command-line client, the client sends LIST. When you type get report.csv, the client sends RETR report.csv. Client conveniences sit on top of a small, fixed protocol vocabulary. The core of that vocabulary:

  • USER and PASS — present a username, then a password, which crosses the wire as readable text, as we will see shortly.
  • CWD, CDUP, PWD — change directory, go up one level, print the current directory.
  • TYPE — choose the transfer type: TYPE A for text with line-ending translation, TYPE I for an exact binary copy. Choosing wrong corrupts files, a classic covered in the failure modes field guide.
  • PASV / PORT (and their modern successors EPSV / EPRT) — negotiate where the next data connection will be made. These are the mode commands, decoded fully in the four data-connection commands.
  • LIST and NLST — request a directory listing, detailed or names-only. The request goes over control; the listing comes back over data.
  • RETR and STOR — retrieve (download) and store (upload) a file, by far the two most consequential commands.
  • QUIT — end the session politely.

Replies deserve — and get — their own article: FTP commands and reply codes. For today's walkthrough you only need the first digit: 2 means success, 3 means "fine so far, send the next piece," 1 means "starting work, more to follow," and 4 or 5 mean failure, temporary or permanent.

One more property of the control connection matters operationally: it is mostly silent. After login, it carries a few short lines around each transfer and nothing in between. During a two-hour upload, the control connection sits idle the entire time — and idle TCP connections are exactly what aggressive firewalls like to quietly discard. That idleness explains a famous failure pattern we will meet at the end.

What Really Travels on the Data Connection

Three kinds of content, and only these three, ever cross a data connection:

  1. File contents going down — the response to a RETR.
  2. File contents going up — the payload of a STOR or APPE.
  3. Directory listings — the response to LIST, NLST, or the machine-readable MLSD.

That third item is the one to tattoo onto your troubleshooting instincts. Because listings ride the data channel, a broken data channel does not just break transfers — it breaks the innocent act of viewing a folder. The signature symptom of a data-channel problem is therefore "login works, then the file list hangs," which points you at firewalls and mode negotiation rather than at passwords. The systematic diagnosis lives in diagnosing FTP mode failures.

Remember: directory listings travel on the data connection, not the control connection. If login succeeds but listing a folder hangs or fails, the control channel is healthy and the data channel is not — start your troubleshooting there, not at the password.

Each data connection lives for exactly one job. Client and server negotiate endpoints (via PASV or PORT), the connection opens, the bytes flow, the connection closes, and the server confirms completion on the control channel with a 226 reply. Ask for ten files and you will see ten data connections, each with its own handshake and, in passive mode, its own server-side port drawn from the server's configured passive port range — the pool of high ports set aside for this purpose (sizing and firewalling it is covered in configuring passive port ranges).

The TYPE setting also does its work here: in ASCII type, line endings are translated as the bytes cross the data connection; in image (binary) type, the bytes pass through untouched. The control connection is unaffected either way — it is always plain text lines.

The Capture: A Full Session, End to End

Now the centerpiece. The setup: a client at 192.0.2.50 connects to a server at 203.0.113.10, logs in, lists a directory, downloads one file, and disconnects. A packet capture runs on the client. What follows is that capture, reduced to what matters and annotated line by line — the annotations after the # marks are ours, not the protocol's.

First, the opening moments at the packet level. Notice this is an ordinary TCP handshake to port 21, and notice who speaks first once it completes:

192.0.2.50:52144  ->  203.0.113.10:21    TCP  SYN                # client asks to connect
203.0.113.10:21   ->  192.0.2.50:52144   TCP  SYN, ACK           # server agrees
192.0.2.50:52144  ->  203.0.113.10:21    TCP  ACK                # control connection is up
203.0.113.10:21   ->  192.0.2.50:52144   FTP  220 FTP service ready.   # server speaks first

From here on, showing individual packets adds noise, so we switch to the view every capture tool offers: the reassembled text of the control stream. Server replies begin with a three-digit code; lines without a code are the client talking.

220 FTP service ready.
USER alex                              # client offers a username
331 Password required for alex.        # 3xx: fine so far, send the next piece
PASS hunter2                           # the real password, fully readable on the wire
230 User alex logged in.               # 2xx: success — authentication is done
SYST
215 UNIX Type: L8                      # client asks what kind of system this is
TYPE I
200 Type set to I.                     # I = image = binary: bytes will pass untouched
CWD reports
250 CWD command successful.            # now sitting in the reports directory
PASV                                   # "tell me where to connect for data"
227 Entering Passive Mode (203,0,113,10,195,80).   # server's answer — decoded below
LIST
150 Opening data connection for LIST.  # 1xx: starting work — watch the OTHER stream now
226 Transfer complete.                 # the listing was delivered (elsewhere!)
PASV                                   # a NEW negotiation for the next job
227 Entering Passive Mode (203,0,113,10,195,81).   # note: a different port this time
RETR daily-summary.csv
150 Opening data connection for daily-summary.csv (18452 bytes).
226 Transfer complete.                 # file delivered — again, not on this stream
QUIT
221 Goodbye.                           # server closes the control connection

Two lines here repay close reading. The PASS hunter2 line is the security story of plain FTP in one glance: anyone positioned to capture this traffic has the password, no cracking required. And the 227 reply is a small puzzle worth solving by hand: the six numbers are the server's IP address (first four) and the data port (last two, encoded as high byte and low byte). Here, 195 × 256 + 80 = 50000. The server is saying: "for this one transfer, connect to me at 203.0.113.10, port 50000."

And the client did. The capture contains not one TCP stream but three, and the tool's conversation summary makes the architecture visible in a single screen:

Stream 0   192.0.2.50:52144 -> 203.0.113.10:21      control    all the lines shown above
Stream 1   192.0.2.50:52150 -> 203.0.113.10:50000   data       892 bytes — the LIST output
Stream 2   192.0.2.50:52151 -> 203.0.113.10:50001   data       18452 bytes — daily-summary.csv

Read the three streams against the control transcript and the choreography clicks into place. Stream 1 was born just after the first PASV/227 exchange, carried 892 bytes of listing text, and died — its closure is what prompted the server's first 226 Transfer complete. Stream 2 repeated the dance on a different port for the file itself. The file's 18,452 bytes appear nowhere in stream 0; the control connection spent the transfer doing nothing at all.

What the Two-Channel Model Explains

Hold that capture in your head and a family of everyday FTP mysteries stops being mysterious:

  • "Login works, listing hangs." Stream 0 is fine; stream 1 could not be established. Something between client and server — a firewall, a NAT device, a misconfigured passive range — refused the second connection. Our companion piece why firewalls block active FTP explains the most common culprit in depth.
  • "Error 425 or 426." These are the server saying, on the control channel, that the data channel could not be opened (425) or died mid-job (426). The complaint arrives on stream 0, but the problem lives on what would have been stream 1.
  • "The two-hour upload finished, then the session errored anyway." The data connection was busy for two hours; the control connection was idle for two hours — and an idle-connection timeout somewhere quietly dropped it. The bytes arrived; the confirmation had nowhere to go. The failure modes guide covers the fixes.
  • "The firewall needs what opened, exactly?" Port 21 plus a path for data connections — which depends on mode and passive range. One rule is never enough, and now you can explain why.

The model matters double for unattended transfers. A human retries a hung listing; a scheduled job at 3 a.m. just fails, and a naive script fails silently. This is why purpose-built automation tools treat data-channel failure as an expected event — Sysax FTP Automation, for example, builds in retry and error handling so a transient data-connection failure becomes a retried transfer rather than a missing file discovered at 9 a.m.

How to Watch a Session Yourself

Nothing cements this model like seeing your own traffic. The safe way is a small lab — a disposable server and client where you can capture, break, and repeat freely; our FTP lab guide builds one step by step. The short version:

  1. Start a packet capture on the client (or the server, or both), filtered to the server's address.
  2. Run one complete session: connect, log in, list, download one file, quit.
  3. Stop the capture and open the conversation or stream view. Find the port-21 stream and read it top to bottom — it will look exactly like our annotated transcript.
  4. Find each data stream, note its ports, and match it to the PASV reply that announced it. Decode the port math by hand once; you will never forget it.

The server keeps its own record of the same conversation. Any serious FTP server logs each session's commands and outcomes — on Windows, Sysax Multi Server records session activity in its logs, the server's view of the same exchange the capture shows from the client side. When a partner says "your server dropped us," comparing the two views settles the question in minutes.

Quick Reference: Control vs Data

Property Control connection Data connection
Carries Commands and numbered replies File contents and directory listings
Server port 21 (by convention) Negotiated per transfer (e.g. passive range)
Lifetime The whole session One listing or one transfer
How many per session Exactly one Zero to many
Typical failure signature Cannot connect or log in at all Login fine; listings and transfers hang, 425/426

The Model to Keep

FTP is a conversation on one connection that arranges deliveries on others. The control connection, on port 21, is a long-lived exchange of text commands and three-digit replies; every listing and every file travels on a separate, single-use data connection whose endpoints are negotiated fresh each time. Login problems live on the control channel; hanging listings, stalled transfers, and 425-class errors live on the data channel. One glance at which stage failed tells you which connection to investigate.

From here, the natural next steps in this series are FTP commands and reply codes, which turns you loose on the full control-channel vocabulary, and the FTP lab guide, where you can capture all of this yourself. For the mode question we deliberately set aside — who opens the data connection, and toward whom — start with active vs passive FTP explained. And if you just want the port numbers in one place, our blog post What port is FTP? is the quick companion read.

Frequently Asked Questions

Is port 20 the FTP data port?
Only in traditional active mode, where the server dials out from port 20. In passive mode — the default nearly everywhere today — the data connection goes to a high port on the server, chosen from its configured passive port range, so there is no single fixed data port.
Why does FTP open a new data connection for every file?
In FTP's standard stream mode, the sender marks the end of a file by closing the data connection, so each connection can carry exactly one transfer. It is a simple, robust end-of-file signal that needs no length headers — at the cost of a fresh negotiation and handshake per file.
Do directory listings really use the data connection?
Yes. The LIST command travels on the control connection, but the listing text itself is delivered over a data connection, exactly like a file. That is why a data-channel problem makes directory listings hang even though login worked perfectly.
Can someone really read my FTP password in a capture?
Yes — the PASS command carries the password as readable text on the control connection, and file contents cross the data connection unencrypted too. That is why FTPS (FTP over TLS) and SFTP exist for anything sensitive.
What does the 227 Entering Passive Mode reply mean?
It is the server telling the client where to open the next data connection. The six numbers are the server's IP address (first four) plus the port, encoded as two bytes: multiply the fifth number by 256 and add the sixth. So (203,0,113,10,195,80) means "connect to 203.0.113.10 on port 50000."
Does the control connection do anything during a long transfer?
Almost nothing — it sits idle until the transfer ends and the server sends its completion reply. That idleness matters: aggressive firewalls sometimes drop the quiet control connection during a long transfer, which is why very long FTP sessions can fail at the finish line.

From the Sysax team: we build secure file transfer software for Windows — Sysax Multi Server, an FTP, FTPS, SFTP, and HTTPS server, and Sysax FTP Automation for scheduled, scripted transfers. Free trials are on the download page.