A complete reference to TCP control flags — their binary bit positions, hex values, and how they work together in the TCP header to manage connections, flow control, and data delivery across the internet.
I spend a lot of time working with TCP packet headers — whether I'm debugging a connection that won't establish, inspecting traffic with Wireshark, or writing low-level network code. The first thing I always check is the flags field. TCP flags are a set of individual bits inside the TCP header that control the state and behavior of a connection. Each flag occupies a specific bit position, and setting a flag to 1 (binary) activates its function.
The TCP flags field lives in bytes 12-13 of the TCP header (the 13th byte, specifically bits 5-0 of byte 12 and bit 7 of byte 13, depending on how you count). In the standard 8-bit representation that most programmers and tools use, the flags occupy a single byte with 8 defined flags and 1 reserved bit. The six original flags defined in RFC 793 are URG, ACK, PSH, RST, SYN, and FIN. Two more flags — ECE and CWR — were added later by RFC 3168 for Explicit Congestion Notification (ECN). Understanding these flags in binary is essential for anyone doing network programming, packet analysis, or cybersecurity work.
When debugging a connection timeout issue, I used tcpdump and checked the TCP flags byte manually. Seeing only SYN packets with no ACK response told me immediately it was a firewall problem rather than an application bug.
Here is the complete mapping of every TCP flag to its binary bit position, hex value, and decimal value. The flags are ordered by bit position from most significant to least significant within the 8-bit flags byte.
| Flag | Bit | Binary | Hex | Decimal | Purpose |
|---|---|---|---|---|---|
| CWR | 7 | 100000000 | 0x80 | 128 | Congestion Window Reduced |
| ECE | 6 | 010000000 | 0x40 | 64 | ECN-Echo |
| URG | 5 | 001000000 | 0x20 | 32 | Urgent pointer field is significant |
| ACK | 4 | 000100000 | 0x10 | 16 | Acknowledgment field is significant |
| PSH | 3 | 000010000 | 0x08 | 8 | Push function — deliver data immediately |
| RST | 2 | 000000100 | 0x04 | 4 | Reset the connection |
| SYN | 1 | 000000010 | 0x02 | 2 | Synchronize sequence numbers |
| FIN | 0 | 000000001 | 0x01 | 1 | No more data from sender |
In the 9-bit version (which includes the reserved bit at position 0 of the 16-bit word), the layout is: reserved (1 bit) — CWR — ECE — URG — ACK — PSH — RST — SYN — FIN. But when you work with the flags in code, the 8-bit representation above is what you will use 99% of the time. Each flag mask is a power of two, so you can combine them with bitwise OR and test them with bitwise AND.
To check if a flag is set in a TCP header byte: if (flags_byte & TCP_SYN) { /* SYN is set */ }. The flag constants in C are typically defined as #define TCP_SYN 0x02, #define TCP_ACK 0x10, etc. In Python, you can use flags & 0x12 to check for SYN-ACK.
The TCP three-way handshake is the most fundamental sequence of flag combinations, and it is the best way to understand how flags work together. Every TCP connection starts with this exchange, and each step sets specific bits in the flags byte.
Here is a compact code example showing how to construct and check these flag combinations in C:
TCP flags rarely appear in isolation. Most real-world packets carry multiple flags set simultaneously. Here are the most common combinations you will encounter in network traffic and what they mean in binary and hex.
| Combination | Binary | Hex | Common Usage |
|---|---|---|---|
| SYN | 000000010 | 0x02 | Connection initiation |
| SYN-ACK | 000100010 | 0x12 | Handshake step 2 |
| ACK | 000100000 | 0x10 | Acknowledgment |
| FIN-ACK | 000100001 | 0x11 | Connection close |
| PSH-ACK | 000110000 | 0x18 | Data push with ACK |
| RST | 000000100 | 0x04 | Connection reset |
| RST-ACK | 000100100 | 0x14 | Reset with ACK |
| URG-ACK | 001100000 | 0x30 | Urgent data with ACK |
| SYN-URG-ACK | 001100010 | 0x32 | Rare — SYN with urgent acknowledgment |
Notice a pattern? The hex values are simply the sum of the individual flag hex values. FIN-ACK = 0x01 + 0x10 = 0x11. PSH-ACK = 0x08 + 0x10 = 0x18. Once you memorize the six original flag hex values (0x01, 0x02, 0x04, 0x08, 0x10, 0x20), you can read any TCP flag combination at a glance.
To compute the binary flags byte for any flag combination, just OR the masks together. For example, to send a FIN with PSH and ACK: flags = 0x01 | 0x08 | 0x10 = 0x19. In binary that is 000110001. You can verify this on our bitwise calculator by entering the hex values and ORing them.
When I am troubleshooting network issues, Wireshark is my go-to tool, and reading the flags field quickly is a skill you develop with practice. Here is what a typical TCP packet looks like in a capture, broken down byte by byte so you can see exactly where the flags live.
Here is the same logic in Python, which is what I use when I write packet analysis scripts with scapy or raw sockets:
If you are working on a server without Wireshark (which is most of the time for me), tcpdump is what you will use. The tcpdump flags abbreviation uses single letters: S for SYN, . for ACK, F for FIN, R for RST, P for PSH. A SYN-ACK shows as [S.] and a pure ACK shows as [.].
Use our bitwise calculator to experiment with flag combinations. Enter the hex values for SYN (0x02) and ACK (0x10) and OR them together to see the binary result. Or try building a full set of flags and watch how each bit toggles.
TCP flags are individual bits in the TCP header's flags field (bits 8-15 of byte 13), each controlling a specific protocol behavior. There are 8 flag bits: CWR (bit 7), ECE (bit 6), URG (bit 5), ACK (bit 4), PSH (bit 3), RST (bit 2), SYN (bit 1), and FIN (bit 0). When a flag is set to 1, it activates that function. A SYN packet has binary 000000010, an ACK packet has 000100000, and a SYN-ACK has both bits set: 000100010.
The SYN flag occupies bit 1 of the TCP flags byte (the second-least significant bit). Its binary value is 000000010 (0x02 in hex). A plain SYN packet has only this bit set in the flags field. When combined with ACK in a SYN-ACK packet, the binary value becomes 000100010 (0x12 hex), which is SYN (0x02) ORed with ACK (0x10).
In tools like Wireshark or tcpdump, TCP flags are displayed as a compact abbreviation: [SYN], [ACK], [FIN, ACK], [PSH, ACK], etc. The bracketed notation shows which flags are set. Each flag corresponds to a single bit in the TCP header's flags field. For example, [SYN, ACK] means both bit 1 (SYN) and bit 4 (ACK) are set to 1, giving a flags byte value of 0x12. tcpdump also shows a raw flags summary like 'S' for SYN, '.' for ACK, 'F' for FIN, 'R' for RST, 'P' for PSH.
A SYN packet has only bit 1 set, so the flags byte is 000000010 (0x02). A SYN-ACK packet has both bit 1 (SYN) and bit 4 (ACK) set, so the flags byte is 000100010 (0x12). The third step of the TCP three-way handshake is a plain ACK (000100000 or 0x10). You can compute the combined value by ORing the individual flag masks: SYN | ACK = 0x02 | 0x10 = 0x12.
The TCP flags field is 9 bits wide, spanning bits 8-15 of TCP header byte 13 (plus a leading reserved bit). Of these 9 bits, 8 are defined flags: CWR (bit 8), ECE (bit 7), URG (bit 6), ACK (bit 5), PSH (bit 4), RST (bit 3), SYN (bit 2), and FIN (bit 1) in the original RFC notation. The 9th bit (bit 0 of that word) is a reserved bit that must be zero. In most programming contexts, the flags are addressed as an 8-bit byte with the least significant bit being FIN (bit 0) and bit 7 being CWR.