A SYN flood attack never finishes a single connection. It sends the first packet of the TCP handshake, thousands of times a second, from source addresses that do not exist, then walks away. Each packet leaves the server holding a slot open for a client that will never answer.
It is one of the oldest attacks on the internet and still one of the most common. Cloudflare’s 2025 Q2 DDoS threat report, published 15 July 2025, put SYN floods second among all network-layer vectors at 27% of attacks, down from 31% the quarter before.
The short version
- It attacks a queue, not a server. The target is the SYN backlog: the fixed-size table where the kernel remembers half-finished handshakes. Fill it and new connections are refused, no matter how much CPU or bandwidth is idle.
- Spoofed source addresses are the entire trick. The server replies to an address that cannot answer, so the entry sits there until it times out. Real addresses would send a reset and free the slot immediately.
- Modern defenses genuinely handle this one. SYN cookies are on by default in Linux, and edge scrubbing providers proxy the handshake before it reaches you. This is the vector the industry solved.
- Which means it tells you almost nothing about full-connection capacity. A half-open connection costs a kernel table entry. A completed one costs a socket, a file descriptor, a conntrack entry and often a worker.
- Obsidio does not run a SYN flood. The nearest simulation, TCP Connection Flood, completes real handshakes from real devices, which is the case your firewall and load balancer actually struggle with.
This post is an explainer rather than part of our ten-part simulation series, because a SYN flood is not one of the ten types Obsidio runs, and the reason why is the most useful thing in here. For how the vector families relate to each other, see our overview of the types of DDoS attacks; for how to structure a first authorized run, start with the guide on how to test your DDoS protection.
What is a SYN flood, mechanically?
Every TCP connection opens with a three-step exchange. The client sends a SYN to say it wants to talk. The server replies with a SYN-ACK to say it is willing, and reserves memory for the coming connection. The client sends a final ACK, and the connection is established.
Between step two and step three the connection is half-open. The server has committed state and is waiting. That state lives in a per-listener queue, usually called the SYN backlog, and on Linux each entry sits in SYN_RECV until the ACK arrives or the entry expires.
A SYN flood sends step one and never sends step three. Each packet is 40-odd bytes and costs the sender nothing. Each one costs the server a backlog entry that will be held for as long as the kernel keeps retrying the SYN-ACK.
On Linux the relevant knob is tcp_synack_retries, documented in the kernel’s networking sysctl reference with a default of 5, “which corresponds to 31 seconds till the last retransmission with the current initial RTO of 1 second”. Half a minute of free occupancy per packet, and the packets arrive by the thousand.
When the backlog is full, further SYN packets are dropped. From the outside the site is simply unreachable. From the inside, CPU is low, bandwidth is low, the application logs are quiet, and nothing is broken except the ability to accept a new connection.
Picture a receptionist with a desk that holds twenty message slips. Twenty callers each say “hold on, I’ll be right back with my name” and never return. The receptionist is not busy; the desk is just full, and the twenty-first caller is told to go away.
Why does source-address spoofing matter so much?
The attack depends on the server’s reply going nowhere. RFC 4987, “TCP SYN Flooding Attacks and Common Mitigations”, published in August 2007, is blunt about it: “For an effective attack, it is important that the spoofed IP addresses be unresponsive to the SYN-ACK segments.” If the forged address belongs to a live host, that host receives an unsolicited SYN-ACK, does not recognise it, and sends a reset. The reset frees the backlog entry instantly and the attack collapses.
So attackers forge addresses that are dark: unallocated space, or ranges with nothing listening. That has three consequences worth holding onto.
- Per-source rate limiting has nothing to count. Every packet appears to come from a different address, and none of those addresses will ever send a second packet.
- Blocklisting is useless and dangerous. The addresses in your logs did not send the traffic. Blocking them punishes uninvolved networks, sometimes including your own users.
- The attack requires the ability to forge packets at all. That is a property of the attacker’s upstream network, not of your defenses.
Which is why the oldest structural fix is not on the victim’s side. RFC 2827, better known as BCP 38, published in May 2000, asks every network to filter outbound traffic so that it can only carry source addresses from the ranges that network actually announces. Adoption is partial after a quarter of a century. CAIDA’s Spoofer project, which continuously measures source-address validation from volunteer vantage points, showed 233 of 1,430 tested IPv4 blocks as spoofable when we checked its summary page on 29 July 2026, roughly one in six once NAT cases are excluded.
The history is worth a line. CERT Advisory CA-1996-21 documented SYN flooding and IP spoofing in September 1996, prompted partly by an attack that took down the mail servers of New York ISP Panix.
Thirty years on, Cloudflare’s 2025 Q3 report of 3 December 2025 still listed SYN floods third among network-layer vectors, behind UDP and DNS floods and ahead of ICMP. Together those four made up just over half of all network-layer attacks in a quarter where Cloudflare mitigated 8.3 million attacks overall.
Which of your controls should have caught this?
It is worth walking the whole chain a connection passes through. For most attacks in this series the answer is uncomfortable. For this one it is mostly reassuring, and saying so plainly matters more than making every control look broken.
Zone 1
Should any of these have stopped it?
- DDoS protection and scrubbing. This is the vector these services were built for. The scrubbing centre answers the handshake itself and forwards only connections a real client completed. It holds, provided your traffic routes through it and your origin is not reachable directly.
- Firewall and WAF. Pull the two apart. A WAF inspects requests and no request is ever sent, so it sees nothing. A stateful firewall does see it, and can become the bottleneck itself if its state table is smaller than the server’s backlog.
- Rate limiting. Keys on source address or on requests. The sources are forged and never repeat, and no request arrives to be counted.
- Bot detection and challenges. A challenge needs a session to challenge. The connection never opens.
- CDN cache. Nothing cacheable is in play. It matters only because a CDN keeps your origin address off the path, and that is the part which decides this.
Zone 2
What takes the hit?
- Load balancer or reverse proxy. Whatever terminates TCP first owns this problem. If the flood reaches you at all, the accept queue and connection state here are what fill up.
- Connection layer. The SYN backlog is the actual target. SYN cookies turn a memory-exhaustion problem into a cryptographic-CPU one, which is a much better trade but not a free one.
- Web server. The kernel handles the half-open queue. The server process is never handed a connection, so worker slots and request handling stay untouched.
- Application and database. Never reached. No request is ever completed, so no query is ever issued.
- Auto-scaling. Watches request rate, latency and CPU. Half-open connections are not requests, so the signals stay flat while the service is unreachable.
Zone 3
Would you find out?
- Dashboards. Packets per second and new connections per second do move sharply, unlike a slow attack. Whether you notice depends on whether anyone graphs TCP connection state rather than only HTTP metrics.
- A check from outside your network. Still the only thing that reliably tells you real users are being refused, since every internal metric can look calm.
- Logging and your SIEM. No access-log lines, because no request completes. Firewall and flow logs do carry it, if you collect and retain them.
- Alerting. Fires if you have a threshold on connection state or packet rate. Most alert sets watch error rate and response time, which do not move here.
- On-call. Usually paged eventually, by a customer or by your scrubbing provider, rather than by your own monitoring.
Purple marks what only a test on your own infrastructure can settle. Everything else follows from how the attack works, not from how well your team configured things.
Compare that grid with the one on the Slowloris post and the verdicts largely invert. Volume-based scrubbing is blind to a slow attack and decisive against a SYN flood. That inversion is the argument for coverage across vector families.
How do you mitigate a SYN flood?
Four controls carry almost all of the weight, and three of them are already on in a default modern deployment.
- SYN cookies. Instead of storing state for a half-open connection, the server encodes what it needs into the sequence number of its own
SYN-ACKand forgets the connection. If a legitimateACKcomes back, the state is reconstructed from the number the client echoes. RFC 4987 also gives the limits: incompatible with some TCP options, and no handling of data piggybacked on theSYN. On Linux,tcp_syncookiesdefaults to1, which the kernel documentation describes as sending cookies “when the syn backlog queue of a socket overflows”, so normal connections are unaffected. - Backlog sizing.
tcp_max_syn_backlogis a per-listener limit on rememberedSYN_RECVrequests. The kernel docs give a minimum of 128 on low-memory machines, scaling with available memory. Raising it buys headroom, and only headroom: a large queue fills more slowly than a small one and still fills. RFC 4987’s note that typical defaults then ranged “from a half-dozen to several dozen” is a good reminder of how much this has already improved. - Faster expiry of half-open state. Lowering
tcp_synack_retriesshortens how long each unanswered handshake occupies a slot. The cost is real: clients on genuinely lossy mobile networks sometimes need those retries, so this is a trade rather than a win. - SYN proxying at the edge. A scrubbing service or capable appliance completes the handshake on your behalf and forwards only connections that a client actually finished. This is the strongest control, because the flood terminates on infrastructure sized for it. It also has the same precondition as every other edge defense: an origin address that is not reachable around it.
That last precondition is where real deployments fail. A protected hostname in front of an origin whose address still answers on port 443 is not protected, and nothing in a configuration review makes that visible.
Why is a SYN flood attack a poor test of connection capacity?
Here is the part that matters if you are planning a resilience test rather than reading a glossary. A SYN flood measures one thing: whether the first device that terminates TCP can survive being asked to remember handshakes that never complete. In 2026 the answer is usually yes, because SYN cookies exist and edge proxying works.
Completed connections are a different problem. A fully established, idle TCP connection consumes a socket and a file descriptor on the server, an entry in the connection-tracking table of every stateful device on the path, and a slot against any per-IP or global connection limit. SYN cookies do nothing about any of that, because from the stack’s point of view these connections are entirely legitimate. They were opened by real hosts that answered honestly.
This is why Obsidio’s catalogue includes TCP Connection Flood and not a SYN flood. The simulation opens raw TCP connections, completes the handshake, and holds each socket idle for up to the configured timeout before recycling it, with a default hold of ten minutes and up to a hundred sockets per worker. Because the traffic comes from 100,000+ globally distributed real devices with real routable addresses, per-IP connection caps get tested against genuine source diversity rather than against a handful of datacenter hosts, and the conntrack tables on every device in the path fill with entries that no cookie trick can shed.
A TLS Flood goes one layer further again, completing the TLS negotiation and paying the server roughly fifteen times the client’s crypto cost before abandoning the socket. Half-open, fully open and fully negotiated test three different resources.
What you can check yourself, and what it will get wrong
Two of these questions you can answer today without any traffic, and it is worth knowing which.
Read the configuration. Confirm tcp_syncookies is enabled, look at your actual backlog and retry values, and check the state-table limits on every stateful device in the path, not just the server. This tells you the settings exist. It does not tell you which limit is smallest, and the smallest one is the one that decides the outcome.
Confirm your origin is unreachable directly. If an edge service is the control you are relying on, verify from outside that the origin address does not answer. This is a genuine test of a genuine dependency and it needs no attack traffic.
Test alert routing on its own. Fire a synthetic alert at the on-call rotation and see whether anyone acts. That verifies the plumbing, and says nothing about whether a threshold exists on TCP connection state, which is the signal that would have moved.
What a small self-run test gets wrong is more interesting. Traffic from one or two hosts is caught by per-source controls immediately, so the front of the chain appears to work perfectly. That conclusion is backwards: those are precisely the controls that behave differently against real source diversity.
How Obsidio tests the connection layer
Obsidio runs connection-exhaustion simulations as controlled, authorized tests against infrastructure the customer owns. Domain ownership is verified by DNS TXT record before any traffic flows. Per the platform FAQ, most institutions start in a controlled window with conservative limits and ramp up as confidence grows, and live metrics let a run be aborted instantly.
For a TCP Connection Flood the numbers to watch are not the request-rate graph, which counts socket opens rather than throughput and will look trivially small while the test is succeeding. Watch active and peak concurrent connections, and watch them alongside the connection-table utilisation on your own load balancer and firewall. That pairing is what tells you which limit is binding.
Two answers stay on your side of the line. Obsidio can report what your edge controls did and how many connections were held, because that is observable from outside. Whether your SIEM recorded anything and whether anyone was paged live only in your own consoles, so somebody has to be watching them during the window.
Strength is proven, not promised. A SYN flood asks whether your kernel can forget a handshake. The harder question, and the one Obsidio actually measures, is what happens when a hundred thousand real devices complete one and refuse to hang up.
Where this fits in a testing programme
Treat the classic SYN flood as a control you verify rather than a scenario you rehearse. Check that cookies are on, that your edge proxies handshakes, that your origin is not reachable around it, and move on. Cloudflare’s 2025 Q4 report of 5 February 2026 counted 47.1 million DDoS attacks across the year, network-layer attacks rising to 34.4 million from 11.4 million in 2024, so the volume is real. The mitigation is also mature, and a test window spent here buys little.
The exhaustion tests worth a window are the ones that use legitimate connections, because no cookie, no challenge and no reputation list can distinguish them from your customers. Those are the runs where a per-IP cap, a conntrack limit or a load balancer’s session table turns out to be the number that decides whether your service stays up.
For regulated institutions the run also has to leave a record. Obsidio produces cryptographically attested, tamper-evident reports generated inside Trusted Execution Environments and mapped to FINMA, DORA and NIS2, so the outcome of a test is an artifact you can file rather than a screenshot you have to vouch for.
To scope an authorized connection-exhaustion simulation against your own infrastructure, see the Obsidio platform or get in touch with the team. Independent, neutral, verifiable: resilience you can prove.
