Flow control protects the receiver, while congestion control protects the network path. Both of them run inside the TCP sender, though. RFC 5681 settles the relationship in one line: “The minimum of cwnd and rwnd governs data transmission.” The receiver advertises rwnd, whereas the sender computes cwnd on its own. So the popular exam answer separates the two by OSI layer. That answer describes flow control as a general idea, rather than TCP’s flow control. What really separates them is the thing each one is protecting.
A TCP sender can send too fast for two entirely different reasons. Either the receiver cannot keep up, or the path between them cannot. Flow control handles the receiver case, while congestion control handles the path.
This guide reads the two governing RFCs directly. RFC 5681 defines TCP’s congestion control, and RFC 9293 defines the window that flow control rides on. Where the popular comparison tables disagree with those documents, the RFC wins here.

What Each One Actually Protects
Start with the two variables, since everything else follows from them. RFC 5681 defines both of them in a single paragraph. The congestion window is “a sender-side limit on the amount of data the sender can transmit into the network”.
The advertised window is its mirror image. That mirror is “a receiver-side limit on the amount of outstanding data”. The pair therefore differs in who the limit is guarding. One protects a buffer, whereas the other protects a path.
Flow control looks after the receiver. A fast server can produce data quicker than a small client reads it, and the client’s buffer would then overflow. Therefore the receiver publishes a number that caps what the sender may leave outstanding.
Congestion control looks after everything between the two hosts. Routers hold queues, and those queues are finite. When too many senders push at once, the queues fill and routers drop packets.
Both limits bind at the sender, though only one of them originates there. The receiver advertises its window, while the sender computes its own. TCP can track either number because it is connection oriented, a model our connection oriented vs connection less guide covers.
How Flow Control Works
TCP flow control is a single number, repeated constantly. Every segment carries a window field, and RFC 9293 gives that field 16 bits.
The meaning of the field is the receiver’s own accounting. It counts the data octets that “the sender of this segment is willing to accept”. In other words, the receiver states how much room remains.
RFC 9293 then ties that number to memory. The advertised window is “related to the data buffer space currently available for this connection”. Flow control is buffer arithmetic rather than path arithmetic.
Nothing forces the receiver to be generous, either. RFC 9293 notes that “Indicating a large window encourages transmissions”. A small window does the opposite, because it throttles the sender directly.
Ignoring the window has a defined consequence. “If more data arrives than can be accepted, it will be discarded.” The waste does not stop there. “This will result in excessive retransmissions, adding unnecessarily to the load on the network and the TCP endpoints.”
The window can also reach zero, which halts the sender completely. A receiver “MAY keep its offered receive window closed indefinitely”, so that pause has no time limit. Therefore the sender probes, and “Probing of zero (offered) windows MUST be supported”.
Zero-window probing exists for one reason. Without it, a reopened window might never reach the sender. The probe guarantees “the reopening of the window will be reliably reported to the other”.
How Congestion Control Works
RFC 5681, titled TCP Congestion Control, is the standard here. It reached standards track in 2009, and it obsoletes RFC 2581.
Congestion control answers a harder question. A sender always knows the receiver’s window, because the receiver keeps sending it. Nobody, however, mails the sender a number for the path.
So TCP guesses, then corrects. Opening a connection into unknown conditions “requires TCP to slowly probe the network to determine the available capacity”. The congestion window holds that running estimate.
Ownership of the algorithm is not shared. “The slow start and congestion avoidance algorithms MUST be used by a TCP sender”. That control covers “the amount of outstanding data being injected into the network”.
The RFC also fixes a ceiling rather than a floor. A sender may be “more conservative than the algorithms allow”. It may not be rougher, though: “a TCP MUST NOT be more aggressive than the following algorithms allow”.
UDP has no equivalent machinery. A UDP datagram carries no window field and no congestion window, so nothing throttles it by default. Our TCP vs UDP guide covers what that trade buys and costs.
Flow Control vs Congestion Control: Comparison Table

The table below sets the two mechanisms against each other, row by row. Every value traces back to RFC 5681 or RFC 9293.
| Aspect | Flow control | Congestion control |
|---|---|---|
| What it protects | The receiver’s buffer | The network path between the hosts |
| Governing variable | rwnd, the receiver window | cwnd, the congestion window |
| Who sets the value | The receiver advertises it | The sender computes it instead |
| Where it is enforced | At the sender | At the sender |
| RFC 5681’s own wording | “a receiver-side limit on the amount of outstanding data” | “a sender-side limit on the amount of data the sender can transmit into the network” |
| Does the value travel | Yes, in the window field of every segment | No, since it never leaves the sender |
| Problem it prevents | Overrunning a slow receiver | Overloading the path |
| What its absence risks | Discarded data, then excessive retransmissions | A sender “more aggressive than the following algorithms allow” |
| Layer inside TCP | Transport, at the sender | Transport, at the sender |
| Layer outside TCP | Also a data link idea between adjacent nodes | Routers queue, drop and can mark ECN |
| Do routers run the algorithm | No | No, though they do generate the signal |
| Signal it reacts to | The advertised window in incoming ACKs | Loss, and optionally ECN per RFC 3168 |
| Scope in TCP | End to end | End to end as well |
| Governing formula | min(cwnd, rwnd) | min(cwnd, rwnd) |
| Defining RFC | RFC 9293 | RFC 5681 |
| Named algorithms | Window advertisement, zero-window probing | Slow start, congestion avoidance, fast retransmit, fast recovery |
| State that drives it | The receiver’s free buffer space | ssthresh, which picks the active algorithm |
| On a slow receiver | rwnd shrinks, and it can reach zero | Unaffected on its own |
| On a congested path | Unaffected on its own | cwnd falls, then climbs back |
| How the two interact | Whichever window is smaller governs | Whichever window is smaller governs |
One row carries the whole article: the row for where each limit binds. Both cells read the same way, at the sender. That is exactly what the layer-based comparisons miss.
The Layer Claim That Does Not Hold

Almost every comparison page separates the two by OSI layer. Flow control gets filed under the data link layer, while congestion control gets the network layer. That split is half right, and the wrong half does real damage.
Here is the half that holds up. Flow control as a general idea genuinely does live at the data link layer. Stop-and-wait and sliding-window schemes run between two adjacent nodes, as our Go-Back-N vs Selective Repeat guide shows. Nobody should mark that wrong in an exam.
Now the half that fails. Those pages are describing TCP rather than a link protocol. RFC 9293 calls TCP “an important transport-layer protocol in the Internet protocol stack”. Its flow control and its congestion control therefore sit in one layer.
They also sit in the same host and the same block of state. RFC 5681 says “two variables are added to the TCP per-connection state” for these algorithms. Those two variables are cwnd and rwnd.
Then comes the arithmetic, which is the strongest evidence available. “The minimum of cwnd and rwnd governs data transmission.” One expression, one sender, both limits.
So the error is not the data link claim. The error is treating layer as the axis that separates the two. In TCP they share a layer, a host and one computation. What actually separates them is the thing each one protects.
Routers are not spectators here, mind you. They queue, they drop, and they can mark packets under the ECN scheme of RFC 3168. Yet no router runs TCP’s congestion control, because RFC 5681 assigns those algorithms to the sender.
Layer maps still matter for other purposes, and our OSI model vs TCP/IP model guide covers those. Use them to place protocols, though, and not to separate rwnd from cwnd.
How the Two Combine in One Sender
RFC 5681 states the combination twice. The definitions section gives the long form, and section 3.1 gives the short one.
The short form is the sentence to memorise. “The minimum of cwnd and rwnd governs data transmission.” Nothing in the standard lets one variable override the other.
The long form spells out the bookkeeping. Data must stop at “the sum of the highest acknowledged sequence number and the minimum of cwnd and rwnd”. The smaller window therefore sets the edge, whichever one that happens to be.
Neither number wins permanently, either. The congestion window changes every round trip, while the advertised window changes whenever the receiving application reads. A connection can be receiver-limited early and network-limited later, or the reverse.
A zero window shows how absolute the rule is. When rwnd reaches zero, no congestion window helps at all. The sender simply waits, and it probes until the receiver reopens.
Both numbers belong to one connection’s state at the sender. TCP therefore has to remember them between segments, unlike a stateless protocol. That per-connection memory is what makes the pair workable.
The Four Algorithms TCP Actually Defines
Many summaries name slow start and congestion avoidance, then stop. RFC 5681’s abstract names twice that many.
Its opening sentence carries the whole scope. “This document defines TCP’s four intertwined congestion control algorithms: slow start, congestion avoidance, fast retransmit, and fast recovery.”
Read the word “intertwined” carefully, since it is the RFC’s own choice. These are not four options to pick between. They hand control to each other inside a single connection.
One variable separates the middle two. RFC 5681 introduces ssthresh “to determine whether the slow start or congestion avoidance algorithm is used”. Slow start runs below that threshold, whereas congestion avoidance runs above it.
The threshold starts out of the way on purpose. “The initial value of ssthresh SHOULD be set arbitrarily high”, so a new connection begins in slow start. Congestion then pulls the threshold down.
Fast retransmit handles loss without waiting for a timer. “The fast retransmit algorithm uses the arrival of 3 duplicate ACKs”. Those duplicates count “as an indication that a segment has been lost”.
Fast recovery then takes over immediately. It “governs the transmission of new data until a non-duplicate ACK arrives”. The sender keeps moving, although on a reduced congestion window.
How Congestion Gets Detected
Textbooks usually say that packet loss is the congestion signal. RFC 5681 is more careful than that.
Its algorithms do work “using loss as the signal of congestion”. The document then widens the picture in the very next sentence. “Explicit Congestion Notification (ECN) could also be used” as RFC 3168 specifies.
So loss is the signal these particular algorithms use, rather than the only signal available. That distinction matters in interviews. ECN lets a router flag congestion before it has to drop anything.
TCP spots loss two ways, and RFC 5681 covers both. The retransmission timer catches it slowly, while three duplicate ACKs catch it quickly. Fast retransmit exists precisely to avoid waiting for the timer.
Either way, the reaction is the same in kind. A sender in fast recovery keeps transmitting on a reduced window, “since loss is an indication of congestion”. Caution, in short, is the standard’s default posture.
Which One Is Your Bottleneck
On a live connection, only one of the two limits binds at a time. Working out which one it is changes what you fix.
One of them is visible on the wire. The receive window travels in the header of every segment, so a packet capture shows it. The congestion window never leaves the sender. RFC 5681 calls cwnd “A TCP state variable that limits the amount of data a TCP can send”.
Small advertised windows point at the receiver. The field itself holds 16 bits, though “The value is shifted when the window scaling extension is used”. Without that extension, the field alone caps how much data can be outstanding.
A window that reaches zero is clearer still. The receiving application is not draining its buffer, and no sender-side change fixes that. RFC 9293 lets the receiver hold the window closed indefinitely.
Loss and retransmissions instead point at the path. The congestion window is the limit that falls in that case, so receiver tuning will not help. Our latency vs throughput guide explains why the resulting throughput drop is not a latency problem.
The honest summary is short. Compare the two windows, and then treat the smaller one as the thing to work on.
Interview Questions
Frequently Asked Questions
Wrapping Up
The two mechanisms answer different questions. Flow control asks whether the receiver can absorb more, while congestion control asks whether the path can carry more. RFC 5681 keeps both answers in one place, at the sender.
Remember the arithmetic rather than the layer diagram. The minimum of the two windows governs transmission, so the binding limit shifts as conditions change. That single line settles most of the exam questions on this topic.
Related reading on DiffStudy:
- TCP vs UDP
- Connection Oriented vs Connection Less
- OSI Model vs TCP/IP Model
- Go-Back-N vs Selective Repeat
- Stateless vs Stateful Protocols
- Latency vs Throughput