TFTP is a protocol that often gets a bad rap for being insecure and slow, but its true genius lies in its utter simplicity, making it incredibly robust for its intended purpose: booting devices on a network where a full TCP stack might not yet be available.

Let’s watch TFTP in action. Imagine a network switch that needs to download its operating system image from a TFTP server before it can fully join the network.

First, the switch, acting as a TFTP client, broadcasts a request to find a TFTP server on the local subnet. Let’s say it’s looking for an image named switch_os_v1.2.bin.

[Switch (Client)] -> Broadcast: TFTP Read Request for "switch_os_v1.2.bin"

A TFTP server, listening on UDP port 69, receives this request. If it has the file, it acknowledges the request and immediately starts sending the file in small, fixed-size blocks, typically 512 bytes. The server uses a new, ephemeral UDP port for this data transfer.

[TFTP Server] -> Switch: TFTP Data (Block #1, 512 bytes) from UDP 12345

The switch receives the first block and, if it’s correct, sends back a TFTP Acknowledgement (ACK) for that block number.

[Switch (Client)] -> TFTP Server: TFTP ACK (Block #1) to UDP 12345

This ACK is crucial. It tells the server that the block was received and that it can send the next one. The server then sends Block #2.

[TFTP Server] -> Switch: TFTP Data (Block #2, 512 bytes) from UDP 12345

And the cycle continues: the client receives data, sends an ACK, and the server sends the next data block. This handshake for every single block is what makes TFTP "trivial" and also relatively slow compared to protocols like FTP or HTTP.

The problem TFTP solves is bootstrapping. Many network devices, like routers, switches, and diskless workstations, need to load their operating system or configuration from a central server before they have a full network stack or even an IP address configured. TFTP, using UDP, is lightweight enough to be implemented in the most basic firmware, often using only MAC addresses or pre-configured IP addresses to initiate contact.

The internal workings are disarmingly simple. TFTP defines five packet types:

  • RRQ (Read Request): Client asks for a file.
  • WRQ (Write Request): Client wants to send a file to the server.
  • DATA: Server sends file data, or client sends file data (for WRQ).
  • ACK: Acknowledges receipt of a DATA packet.
  • ERROR: Indicates an error condition.

The entire protocol is built on these simple request/response pairs, with each data block requiring an acknowledgment. This makes it inherently reliable in the face of packet loss, as a missing ACK will cause the sender to retransmit the block.

The TFTP server process on the server machine is typically a daemon that listens on UDP port 69 for initial RRQ or WRQ requests. Once a transfer begins, it switches to a higher, dynamically allocated UDP port for the actual data exchange. The client does the same, using its own ephemeral port for the transfer.

A common misconception is that TFTP is inherently insecure. While it lacks authentication and encryption, its "insecurity" is often a function of how it’s deployed. When used on a trusted internal network for device booting, the lack of security is less of a concern than the simplicity and low overhead. If you need security, you’d typically use SCP or SFTP, which run over SSH.

The way TFTP handles file transfer is block-oriented. The maximum block size is 65535 bytes, but 512 bytes is the most common default. The protocol uses a 16-bit block number, meaning a single transfer can only be up to 64MB (2^16 blocks * 512 bytes/block). For larger files, TFTP clients and servers need to implement a mechanism to wrap around the block numbers or negotiate a larger block size, though this is not part of the original RFC.

The next logical step after understanding TFTP is to see how it interacts with bootloaders, particularly in embedded systems or network hardware.

Want structured learning?

Take the full Computer Networking course →