Protecting RDP from DDoS attacks and brute force

Published on 41 min read

Brute force, logon floods and volumetric DDoS all look alike on an RDP server and need opposite countermeasures. Tell the three apart by their signatures, lock down port 3389 properly, and know when only upstream filtering helps.

A Windows server with Remote Desktop open to the internet does not have one problem, it has two, and they are almost always confused with each other. One is a brute force attack: somebody works through usernames and passwords, the Security log fills up with failed logons, and the server stays reachable the whole time. The other is a DDoS attack: somebody generates so many half-open connections or so much traffic that port 3389 stops answering at all, and nobody is trying to log on. To the operator both feel identical, namely "RDP is down". The countermeasures, however, pull in opposite directions, and mixing them up either locks you out of your own server or leaves the wrong hole open.

This article sorts out DDoS protection for RDP from an operator's point of view. It explains what RDP actually does on the wire, which ports belong to it, how to tell brute force, logon flood and a real volumetric attack apart by their signatures, what a SYN flood against port 3389 triggers inside Windows, which firewall rules and policies actually accomplish something, which widely quoted registry values have had no effect since Windows Server 2008, and where the line runs beyond which no setting on the server helps any more. If your server is unreachable right now, jump straight to "What to do during an attack".

Why RDP servers get attacked

RDP stands for Remote Desktop Protocol and it is the protocol Windows uses to deliver an entire desktop over the network. That makes it the one service on an ordinary Windows server where a single correct password means complete control of the machine. This is exactly why it sits at the top of every scanner list.

How central RDP is to attackers is shown by the 2025 Sophos Active Adversary Report, which evaluates 413 investigated incidents from 2024. RDP was used by attackers in 84 percent of all cases, in 67 percent exclusively for internal lateral movement and in 3 percent exclusively from outside. Adding the cases that used both brings the totals to 83 percent internal and 19 percent external. The same report names compromised credentials as the root cause of initial access in 41 percent of cases, exploited vulnerabilities in 22 percent and brute force in 21 percent.

For the DDoS question this yields an important distinction. Most of what looks like an attack on an RDP server is not an overload attack, it is a takeover attack. A DDoS attack wants to take your service away, a brute force attack wants to have it. Anyone who tightens the account lockout out of fear of DDoS, and limits connections out of fear of brute force, has turned the wrong dial both times.

RDP in technical terms: what happens during connection setup

RDP listens on port 3389 TCP by default. Since RDP 8.0, meaning since Windows 8 and Windows Server 2012, port 3389 UDP is added as an accelerated transport for graphics, input and multimedia. Microsoft lists both together in the official port overview for Remote Desktop Services: "TCP and UDP 3389: Standard Remote Desktop Protocol (RDP) port." If the UDP path fails, the session falls back to TCP. This dual nature matters for any attack discussion, because TCP and UDP are attackable in completely different ways.

Connection setup follows a fixed sequence defined in the Microsoft specification MS-RDPBCGR, and every stage costs the server more than the one before it:

  1. TCP handshake. Three packets: SYN, SYN-ACK, ACK. For an incoming SYN the server creates an entry in its queue of half-open connections. Measured by ratio, this is the cheapest point for an attacker and the most expensive one for the server.
  2. X.224 Connection Request. The client sends a TPKT header, the X.224 connection request, an optional routing cookie in the form mstshash= and a structure called RDP_NEG_REQ. Its requestedProtocols field states which security layer the client wants to speak: legacy RDP security, TLS, or PROTOCOL_HYBRID with the value 0x00000002, which means CredSSP and therefore Network Level Authentication.
  3. X.224 Connection Confirm. The server replies with its choice, or with a failure structure if it supports none of the offered protocols.
  4. TLS and CredSSP handshake. Only here are credentials checked. This costs CPU time for cryptography and a certificate operation.
  5. MCS Connect Initial. After this the actual RDP session begins, possibly preceded by an Early User Authorization Result PDU.

Network Level Authentication, NLA for short, moves the password check to stage 4 and prevents an anonymous connection attempt from creating a session, a logon screen and the memory that goes with it. That is a genuine gain against logon floods and the reason NLA appears in every hardening guide, including ours in Secure RDP on Windows Server. Against a SYN flood, however, NLA does nothing at all, because a SYN flood stops at stage 1 and never reaches stage 2. You have to know this difference, otherwise you expect the wrong effect from the right measure.

The ports around RDP at a glance

The following table lists the ports Microsoft names in the official port overview for Remote Desktop Services. It answers the first question anyone asks before writing a firewall rule, namely what actually has to be open.

Port and protocol Role Used for Must it face the internet?
3389 TCP RD Session Host standard RDP, connection setup and session no, it belongs behind a VPN or an RD Gateway
3389 UDP RD Session Host accelerated transport since RDP 8.0, falls back to TCP when needed no, and better blocked if unused
443 TCP RD Gateway and RD Web Access RDP inside HTTPS, configurable in the RD Gateway management console yes, this is the intended path from outside
3391 UDP RD Gateway RDP over UDP to the gateway, configurable in the management console optional, only for the accelerated transport
5504 TCP RD Connection Broker connections to RD Web Access no, internal only
5985 TCP all RDS roles WMI and PowerShell Remoting for administration no, never
135 TCP and 49152 to 65535 TCP RD Licensing Server RPC endpoint mapper and dynamic RPC ports on Windows Server 2008 and later no, internal only
445 TCP, 139 TCP, 137 UDP, 138 UDP RD Licensing Server and broker paths SMB and NetBIOS no, under no circumstances

The practical core of this table sits in the last column. For remote access from outside there is exactly one intended port, namely 443 TCP through an RD Gateway, and anyone not running one uses a VPN instead. Port 3389 directly on the internet is the intended path in none of these rows. It is the shortcut most operators take.

Brute force, logon flood or DDoS: the distinction everything depends on

Three completely different events produce the same symptom on an RDP server. They differ in which stage of the connection setup they stop at, and that is exactly how you recognize them.

Case 1: brute force against the logon

A brute force attack builds every connection completely, so it reaches stage 4, and works through credentials there. It consumes almost no bandwidth. Ten attempts per second are less than 1 Mbit/s and completely unremarkable for the link. The server stays reachable, real users often notice nothing at all, and yet this is the more dangerous of the three cases, because it aims at takeover rather than outage.

Signature in the Security log: many events with ID 4625 (failed logon). Alongside them event 4740 as soon as an account lockout triggers. A successful Remote Desktop logon carries ID 4624 with logon type 10. In the log Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational, event 131 records every accepted TCP connection with its source address, and event 140 records a logon failure with its source address. Event 140 has a quirk worth knowing: it is written only if the attempted username does not exist on the system or in the domain. If somebody works through valid usernames, 140 stays silent and you depend on 4625 together with 131.

Signature on the network: few source addresses with very many complete connections, or very many source addresses with a few attempts each if the attacker spreads out. In both cases the packet rate is low and the average packet size is normal.

What helps: account lockout, strong passwords, NLA, address restriction. What does not help is anything that tunes the connection rate, because a brute force attack comfortably stays under any rate limit you would still impose on a real user. The full procedure is in Secure RDP on Windows Server, and the way out of a triggered lockout is in Fix the RDP account locked out error.

Case 2: logon flood and connection flood

A logon flood is a layer 7 attack that looks like ordinary traffic because it is ordinary traffic, only in the wrong quantity. The attacker builds complete TCP connections and makes the server work through the TLS and CredSSP handshake every single time, then aborts and starts over. That is considerably more expensive than a brute force attempt, because every connection triggers a cryptographic negotiation, and considerably cheaper than a volumetric attack, because bandwidth stays low.

Signature in the Security log: conspicuously few 4625 events relative to the load. That absence is the clue. When CPU rises and the service stalls but hardly any failed logons are recorded, the traffic is not reaching the logon at all. In the RdpCoreTS log, by contrast, the number of 131 events climbs sharply, because every accepted connection is recorded there.

Signature on the network: many short-lived, fully established connections to port 3389, often from a few hundred source addresses. The count of connections in state Established swings wildly, while the count in state SynReceived stays low.

What helps: address restriction and a limit on concurrent sessions. Windows Firewall cannot rate limit connections, it simply has no such feature. Effective per source rate limiting for RDP therefore exists only in front of the server, not inside it.

Case 3: volumetric DDoS attack

A volumetric attack does not care that a service is listening on port 3389. It fills the link, and your RDP becomes unreachable because there is no room left in front of it. The attack traffic does not even have to be aimed at port 3389: a UDP flood against any port on the same IP address has exactly the same effect. The fundamentals are covered in What is a DDoS attack.

Signature in the Security log: none. That is the single most important statement in this section. A volumetric attack leaves no trace whatsoever in the Security log, because not one packet makes it to the logon. Anyone looking in Event Viewer for proof of a DDoS attack is looking in the wrong place.

Signature on the network: a high packet rate with normal or low CPU load, rising discard counters on the network adapter, and a service that answers normally over 127.0.0.1 but not from outside. The average packet size reveals the construction: bytes divided by packets below 100 bytes points to a protocol attack, above 1,000 bytes to an amplification attack.

What helps: filtering in the network in front of the server, and nothing else. Every firewall rule on the server decides about a packet that has already traveled down the wire.

Telling the three cases apart by their signatures

Characteristic Brute force Logon flood (layer 7) Volumetric DDoS
Stage where it stops stage 4, password check stage 4, abort after the handshake stage 1 or earlier
Event 4625 in the Security log very many few to none none
Event 131 in RdpCoreTS many very many none, or aborting
Event 140 in RdpCoreTS many, but only for unknown usernames none none
Connections in state SynReceived low low very high during a SYN flood
Inbound bandwidth unremarkable, usually below 1 Mbit/s low to moderate at the limit of the link
CPU load low clearly raised by TLS and CredSSP often unremarkable
Other services on the same IP address unaffected unaffected gone as well
Effective countermeasure account lockout, NLA, address restriction address restriction, session limit, filtering upstream filtering in the network in front of the server only

The row that produces clarity fastest in practice is the second to last one. If other services on the same IP address are gone too, it is the link and not RDP. If a web server on the same machine keeps answering normally while only 3389 hangs, you have an RDP problem and not a bandwidth problem. That single check replaces half an hour of log reading. The full measurement procedure is in Detect a DDoS attack on your server.

SYN floods against port 3389 and the half-open connection

This is the difference that separates RDP from a UDP based game service. RDP primarily speaks TCP, and TCP has a state that UDP does not: the half-open connection.

A SYN flood is an attack in which the attacker sends TCP packets with the SYN bit set and a forged source address. For every packet the server creates an entry in its queue of half-open connections, answers with SYN-ACK to an address that never asked, and waits. The third packet of the handshake never arrives. The entry sits there until it expires.

The asymmetry is brutal. On the wire a SYN packet is as small as an Ethernet frame is allowed to be, namely 64 bytes including the frame check sequence, and it costs the attacker nothing. For it, the server has to allocate memory, generate a reply, start a timer and repeat that reply several times. At 1 Gbit/s roughly 1.49 million such packets per second fit on the wire. Any queue working with a few thousand slots is therefore mathematically full in under a millisecond. In practice the network adapter and the kernel give up well before that.

Two properties make a SYN flood particularly unpleasant for the defender. First, the source address can be forged, because the attacker never has to see the reply. A blocklist by source address therefore goes nowhere, since the addresses are invented and change with every packet. Second, the attack needs almost no bandwidth if the table alone is the target. A link that looks quiet on the bandwidth graph can still be under a SYN flood.

What Windows does during a SYN flood

Windows has had built in SYN attack protection since Windows Vista and Windows Server 2008. Microsoft describes it in its own documentation on TCP/IP stack hardening with three properties:

  • The protection is enabled by default and cannot be disabled.
  • It calculates its thresholds dynamically from the number of CPU cores and the amount of available memory, and therefore deliberately exposes no configurable parameters through the registry, through netsh or anywhere else.
  • Because the driver decides based on those resources, a system with more cores and more memory starts dropping new connection attempts later than a small one. The algorithm is explicitly built so that no fine tuning is required.

Once Windows enters the attack state, it drops new connection requests as soon as the internally calculated threshold is reached. To your users this looks like a timeout with no error message from RDP at all, and a second attempt sometimes works. Existing sessions keep running, new ones do not come up.

And now the part hardly any guide mentions: Windows does not tell you that SYN attack protection has kicked in. There is no event for it in Event Viewer and no dedicated counter. You can only read the state indirectly from three values, and they are worth knowing:

Get-NetTCPConnection -State SynReceived | Measure-Object | Select-Object -ExpandProperty Count
Get-NetTCPConnection -LocalPort 3389 -State Established -ErrorAction SilentlyContinue | Measure-Object | Select-Object -ExpandProperty Count
Get-NetAdapterStatistics | Select-Object Name, ReceivedBytes, ReceivedUnicastPackets, ReceivedDiscardedPackets

The first command counts half-open connections. A two digit value is normal on an ordinary server, a four or five digit value is a SYN flood. The second shows how many RDP sessions are actually up. The third delivers the network counters with language neutral property names. That is not a detail: the counter paths used by Get-Counter are localized in Windows, so a counter path written in English fails on a German system. Get-NetAdapterStatistics does not have that problem.

Measure these three values once during normal operation and write them down. Without a baseline you cannot say in an emergency whether 3,000 half-open connections is a lot or just Monday morning.

Registry values against SYN floods: what still applies

A list of registry values that supposedly hardens Windows against SYN floods circulates widely on the internet. It comes from a guide for Windows Server 2003 and has been copied from provider to provider ever since. These values have no effect on any currently supported version of Windows. Microsoft has documented this twice in writing: once for the TCP/IP values, once for the AFD driver values, where the associated logic was even removed from the source code.

Value Path under HKLM\SYSTEM\CurrentControlSet Status today
SynAttackProtect Services\Tcpip\Parameters no effect from Windows Vista and Windows Server 2008 onward, the protection is built in and cannot be switched off
TcpMaxHalfOpen Services\Tcpip\Parameters no effect, the threshold is calculated dynamically
TcpMaxHalfOpenRetried Services\Tcpip\Parameters no effect
TcpMaxConnectResponseRetransmissions Services\Tcpip\Parameters no effect
EnableDynamicBacklog, MinimumDynamicBacklog, MaximumDynamicBacklog, DynamicBacklogGrowthDelta Services\AFD\Parameters invalid as of Windows Server 2008, the logic was removed from the AFD driver
UserAuthentication (NLA) Control\Terminal Server\WinStations\RDP-Tcp effective, value 1 forces authentication before the session is created
SecurityLayer Control\Terminal Server\WinStations\RDP-Tcp effective, value 2 forces TLS for the negotiation
PortNumber Control\Terminal Server\WinStations\RDP-Tcp effective, defines the port RDP listens on

You check the three effective values from the lower rows like this:

Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' | Select-Object UserAuthentication, SecurityLayer, PortNumber

Stick to that separation. A value that is set but does nothing is worse than no value at all, because afterwards you believe you are protected. How to move the port cleanly and without a restart is described in Change the RDP port without restarting. Handling NLA and its typical follow-up errors is covered in Fix the RDP Network Level Authentication error.

Why moving the port keeps scanners away but is not protection

A port other than 3389 is a noise reduction measure, not a security measure. That is not a contradiction, it is a precise statement about its effect, and both halves are true.

What it achieves. The bulk of automated scanners walks through address ranges and checks exactly port 3389. If nothing is there, they move on. The measurable effect is substantial: on an affected server the number of 4625 events typically drops by orders of magnitude, and Event Viewer becomes readable again. That is not a cosmetic gain. A Security log that rolls over within hours under brute force noise overwrites precisely the entries you need in an emergency.

What it does not achieve. Against a determined attacker the port change does nothing. A full port scan across all 65,535 ports takes seconds, and search engines for exposed services recognize RDP by its protocol fingerprint regardless of the port: whoever sends an X.224 connection request and gets back a valid connection confirm knows RDP is running there, no matter which number it sits on.

And against DDoS it does nothing at all. A volumetric attack is aimed at your IP address, not at a port number. The attack from May 2025 documented by Cloudflare spread across an average of 21,925 destination ports simultaneously, peaking at 34,517. Hiding from that on a different port hides you from nobody.

The practical conclusion: move the port, but as a supplement and never as a replacement. And create the firewall rule for the new port before you reconfigure the service, otherwise you lock yourself out. The built in Remote Desktop rules in Windows are bound to 3389 and no longer apply after a port change.

The other role: RDP as an amplifier against third parties

One point that practically never appears in RDP guides, although it belongs squarely in this topic: an RDP server with UDP port 3389 open can be not only a victim but a weapon.

In January 2021 NETSCOUT described how the RDP service on UDP/3389 can be abused for reflection and amplification attacks. The figures are unambiguous. The amplification ratio is 85.9 to 1. The resulting reply packets are consistently 1,260 bytes long and padded with long strings of zeroes. At the time of publication roughly 33,000 abusable Windows RDP servers were counted, and the attacks observed with them ranged from about 20 Gbps to 750 Gbps. The technique was added to the toolkits of commercial attack services.

An amplification attack works like this: the attacker sends a small request to your open UDP service and enters the IP address of the victim as the source. Your server dutifully replies, only to the victim, and the reply is 85.9 times larger than the request. For you as the operator this has three consequences, all of them unpleasant: your own outbound bandwidth is consumed, your own remote access can fail in the process, and your IP address ends up on blocklists that are hard to get off again.

The countermeasure is simple and free. If you do not need the accelerated UDP transport, close UDP 3389. You lose nothing except some scrolling comfort at high latency, because RDP falls back to TCP automatically. In the same publication NETSCOUT explicitly recommends making RDP servers reachable only through VPN services, and names closing UDP/3389 as the interim step for everyone who cannot do that immediately.

What helps on the server itself

More can be achieved on the server than is often claimed, namely against everything that stays small: scanners, brute force, single sources and moderate connection floods. All commands below run in a PowerShell session with administrator rights on Windows Server 2016 through 2025, unless stated otherwise.

1. Measure first, change second

Record the starting state before you touch anything. These four lines take less than half a minute and afterwards answer the question of whether a measure worked:

Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4625; StartTime=(Get-Date).AddDays(-1)} -ErrorAction SilentlyContinue | Measure-Object | Select-Object -ExpandProperty Count
Get-NetTCPConnection -State SynReceived | Measure-Object | Select-Object -ExpandProperty Count
Get-NetAdapterStatistics | Select-Object Name, ReceivedBytes, ReceivedUnicastPackets, ReceivedDiscardedPackets
Get-NetFirewallPortFilter | Where-Object { $_.LocalPort -eq 3389 } | Get-NetFirewallRule | Select-Object DisplayName, Enabled, Profile, Action, Direction

The -ErrorAction SilentlyContinue in the first line belongs there: Get-WinEvent aborts with a red error when not a single matching event exists in the chosen period. On a properly hardened server that is exactly the normal case.

The fourth line is the one that most often produces the surprise. It lists every firewall rule touching port 3389. Almost every provider image and many software installers create their own wide open rules there, and as long as one of them exists, restricting the built in rules has no effect. The order in the pipeline is deliberate: reverse it and the call takes many times longer while the rule name is missing from the output.

2. Secure your way back before touching a firewall rule

Every measure in this section can lock you out. On a server you can only reach over RDP that means the end of the session. Three precautions reliably prevent it.

First: confirm you have a console that does not depend on the network. On KVM servers from KernelHost the customer panel offers a VNC console that looks directly at the screen of the virtual machine. It keeps working even when the firewall, the RDP service and the network settings are broken all at once. Open it once as a test before you change anything, not afterwards.

Second: export the entire firewall rule set to a file. A way back in one command is worth more than any note:

netsh advfirewall export "C:\firewall-before.wfw"

You restore it with netsh advfirewall import "C:\firewall-before.wfw", and you can do that from the VNC console when RDP is gone.

Third: keep the RDP session you are working in open during the whole change and test every modification with a second, newly established connection. Existing sessions are not dropped immediately by new firewall rules, while a new connection fails right away. That way you notice the mistake while you can still undo it.

3. Windows Firewall: restricting the scope to known source addresses

This is the measure that genuinely ends attack traffic at the application level, and it ends it completely. It restricts the built in Remote Desktop rules to a list of permitted source addresses. Work with the language neutral group identifier @FirewallAPI.dll,-28752 rather than the displayed group name, because the displayed name is translated and differs between an English and a German system. First look at what will be affected:

Get-NetFirewallRule -Group '@FirewallAPI.dll,-28752' | Select-Object Name, DisplayName, Enabled, Profile, Direction

Expect more hits than you expected rules. The group usually contains several rules per profile. That is correct, because otherwise one of the copies would stay open. Then set it:

Set-NetFirewallRule -Group '@FirewallAPI.dll,-28752' -RemoteAddress @('203.0.113.10','198.51.100.0/24')

And read back which addresses were actually stored:

Get-NetFirewallRule -Group '@FirewallAPI.dll,-28752' | Get-NetFirewallAddressFilter

The proof from outside is one line and should run from a foreign address. The result has to read TcpTestSucceeded : False:

Test-NetConnection -ComputerName 203.0.113.50 -Port 3389

4. The same restriction with netsh advfirewall

If you prefer netsh or need a script for older systems, create your own rule instead of touching the built in ones. Here that is even the more robust path, because a rule you name yourself has no translated name. These commands run in an elevated Command Prompt just as well as in PowerShell:

netsh advfirewall firewall add rule name="RDP office only" dir=in action=allow protocol=TCP localport=3389 remoteip=203.0.113.10,198.51.100.0/24 profile=any
netsh advfirewall firewall show rule name="RDP office only"

An allow rule on its own is not enough while a second, wider rule for the same port exists. Windows Firewall evaluates allow rules together, so the widest one wins. Check with the fourth line from step 1 and either disable the built in rules or restrict them as in step 3.

The same syntax also creates a targeted block against a conspicuous source address. Block rules take precedence over allow rules in Windows Firewall:

netsh advfirewall firewall add rule name="Block attacker" dir=in action=block protocol=any remoteip=203.0.113.99

Have no illusions about the limits of this. A blocklist helps against single sources. Against a distributed attack no list grows fast enough, and every additional entry costs matching time on a system that is already under load.

5. Close UDP 3389 if you do not need the accelerated transport

After the amplification section this is the measure with the best ratio of effort to effect. It closes the amplifier role and at the same time removes an attack surface from the server, because UDP has no connection setup you could demand:

netsh advfirewall firewall add rule name="Block RDP UDP" dir=in action=block protocol=UDP localport=3389 profile=any

In PowerShell the equivalent is:

New-NetFirewallRule -DisplayName 'Block RDP UDP' -Direction Inbound -Protocol UDP -LocalPort 3389 -Action Block -Profile Any

The cleaner path, if you use Group Policy, goes through gpedit.msc: Computer Configuration, Administrative Templates, Windows Components, Remote Desktop Services, Remote Desktop Session Host, Connections, policy "Select RDP transport protocols". Set it to use TCP only. The difference from a firewall rule is that the service then does not listen on UDP at all, instead of the packets being dropped in front of it. Both reach the goal, the policy is the tidier solution.

Afterwards confirm that nothing is listening on UDP 3389 any more:

Get-NetUDPEndpoint -LocalPort 3389 -ErrorAction SilentlyContinue

6. The account lockout policy and its downside

An account lockout is the most effective single measure against brute force and useless against DDoS. It still belongs in this article, because under fire it turns into a trap. Set it in one call, otherwise Windows rejects the duration while the threshold is still 0:

net accounts /lockoutthreshold:10 /lockoutduration:10 /lockoutwindow:10
net accounts

The values 10, 10 and 10 match the baseline Microsoft names as a starting point in the article on KB5020282: lockout after ten failed attempts within ten minutes, lockout duration ten minutes. The duration always has to be greater than or equal to the observation window.

Since the cumulative updates of October 11, 2022 there is an additional policy called "Allow Administrator account lockout", which brings the built in Administrator account under the same lockout rule. On newly installed systems from Windows 11 version 22H2 onward it is already active at initial setup. It lives under Local Computer Policy, Computer Configuration, Windows Settings, Security Settings, Account Policies, Account Lockout Policies.

The downside: an account lockout is also a weapon against you. Anyone who knows your username keeps the account permanently locked by sending eleven wrong passwords every ten minutes. That is a denial of service running on a few kilobits per second, and no filter recognizes it as an attack, because it consists of valid, complete connections. This is precisely why the account lockout is the second line of defense and the address restriction is the first.

One detail defuses the worst case, and it is stated explicitly in Microsoft's own description: the new lockout behavior affects network logons such as RDP only. Console logons are still allowed during the lockout period. So anyone with a VNC console in the customer panel can still reach the machine even with the Administrator account locked.

7. Limit concurrent sessions

Against a connection flood that never attempts a logon, a hard cap on concurrent connections is the right answer. The policy is called "Limit number of connections" and lives in gpedit.msc under Computer Configuration, Administrative Templates, Windows Components, Remote Desktop Services, Remote Desktop Session Host, Connections. On a server where three people work, a small number belongs there rather than the default.

Also set time limits for disconnected and idle sessions, likewise through Group Policy under Remote Desktop Session Host, Session Time Limits. Disconnected sessions that never end hold memory and session slots, and under load every occupied slot is a slot a real user does not get.

How many sessions are running right now and who holds them is shown by the built in command:

query session

8. Log dropped packets

Without a log you are guessing. Windows Firewall can record dropped connections but does not do so out of the box:

netsh advfirewall set allprofiles logging droppedconnections enable
netsh advfirewall set allprofiles logging maxfilesize 32767
netsh advfirewall show allprofiles logging

The upper limit for the file size is 32,767 kilobytes, netsh accepts no more. Under fire this file fills up quickly, so use the full value. The default location is %systemroot%\system32\LogFiles\Firewall\pfirewall.log and the format is text with a header row naming the columns.

In parallel, give the Security log more room, otherwise it overwrites itself within a few hours under brute force:

wevtutil sl Security /ms:1073741824

Then evaluate which addresses the failed attempts come from. Reading through the XML structure is the robust variant, because it does not depend on field order:

Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4625; StartTime=(Get-Date).AddDays(-7)} -ErrorAction SilentlyContinue | ForEach-Object { ([xml]$_.ToXml()).Event.EventData.Data | Where-Object { $_.Name -eq 'IpAddress' } | Select-Object -ExpandProperty '#text' } | Group-Object | Sort-Object Count -Descending | Select-Object -First 15 Count, Name

For failed attempts with an unknown username, where the Security log holds no usable address, the RDP specific log helps:

Get-WinEvent -LogName 'Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational' -FilterXPath '*[System[EventID=140]]' -MaxEvents 50 -ErrorAction SilentlyContinue | Format-List TimeCreated, Message

The real recommendation: RDP does not belong on the open internet

Everything above improves the situation of a server whose RDP faces the internet. The best measure is for it not to face the internet at all. That is not a cautious platitude, it is a reshaping of the problem: an RDP problem becomes a VPN problem, and the VPN problem is the smaller one.

The reason lies in how the services are built. RDP has to answer a connection attempt before it knows who is knocking: it sends a connection confirm, negotiates TLS and only then checks credentials. A modern VPN can behave differently. WireGuard does not answer a packet that carries no valid key at all. To a scanner the port looks like nothing. The entire class of brute force attacks and logon floods disappears with it, not because it is repelled, but because there is nothing left for it to work against.

Option A: a VPN in front of it

The procedure is always the same. You set up the VPN service, test the connection, allow RDP only for the VPN address range and close 3389 on the internet completely. The order matters: verify the VPN first, then close RDP, and do it in a second session while the first one stays open.

The rule for a VPN address range looks like this:

Set-NetFirewallRule -Group '@FirewallAPI.dll,-28752' -RemoteAddress '10.8.0.0/24'

How to set up your own VPN service is described in Set up a WireGuard VPN server. Whether running your own beats a ready made offering is weighed up in Own VPN server versus VPN service. Important for this article: a VPN moves the problem, it does not solve all of it. The VPN service itself still hangs on the same link and is exposed to the same volumetric overload. What a VPN takes care of is the logon side. What it does not take care of is the link. What to do at the VPN port itself, from handshake floods to rate limiting that separates the handshake from the data traffic, is covered in Protect a VPN server from DDoS.

Option B: an RD Gateway on 443

Microsoft's own answer to the same question is called Remote Desktop Gateway. It accepts RDP inside an HTTPS connection on TCP 443, checks authorization against policies and only then passes the session on to the actual server. Optionally UDP 3391 is added for the accelerated transport. Both port numbers can be changed in the gateway management console.

The advantage over a VPN: Windows clients need no additional service, the gateway address is entered directly in the Remote Desktop Connection client. The disadvantage: an RD Gateway is a role of its own with a certificate, a Network Policy Server and maintenance effort, and it faces the internet itself, although with a far smaller attack surface than a bare 3389.

Which option fits depends on the environment. For a single Windows VPS with two or three people needing access, a VPN is the shorter route. For an environment with several session hosts and changing staff, the RD Gateway is the cleaner structure. What both share is what matters: port 3389 has disappeared from the internet afterwards.

Where every measure on the server stops

Now the part no policy and no firewall rule solves. Everything so far runs on your server, meaning at the end of the link. A firewall rule decides about a packet that has already traveled down the wire. You can drop it, but you cannot unsend it. If the link in front is full, your users' packets stop arriving before that point, no matter how good your rule set is.

Link Payload per second Packets per second at 64 bytes What that means for RDP
1 Gbit/s 125 megabytes 1,488,095 an attack of 20 Gbps saturates it twentyfold
2 times 1 Gbit/s 250 megabytes 2,976,190 changes nothing about the order of magnitude
10 Gbit/s 1,250 megabytes 14,880,952 enough for small attacks, not for the observed 750 Gbps
100 Gbit/s 12,500 megabytes 148,809,523 even here an attack of 750 Gbps needs eight times as much

Run that calculation for your own case once. A Windows VPS typically hangs on 1 Gbit/s. The lower edge of the RDP amplification attacks observed by NETSCOUT was around 20 Gbps. That is twenty times what your link can carry at all. In that range the question of the right firewall rule is moot.

There is a second, more unpleasant limit. Once the link is saturated, even the RDP session you wanted to investigate with may not reach you. Anyone without network independent access then sees nothing at all. That is why the VNC console appears repeatedly in this article: in an emergency it is the only path that still works.

What KernelHost puts up against it

The always-on protection included with every server

DDoS protection at KernelHost is built in two layers and permanently active, with nothing for you to switch on, order or configure:

  • Layer 1: 17 Tbps of mitigation capacity in the global scrubbing network. Volumetric attacks are scrubbed close to their source, before they reach the datacenter.
  • Layer 2: Arbor real-time filtering with 3.2 Tbps in Frankfurt am Main. Directly in front of the server, protocol specific patterns are detected and dropped, packet by packet. For RDP that means SYN floods and connection floods against 3389 TCP, as well as UDP based reflection traffic, end there and not on your network card.

Two properties make the difference. The protection runs permanently and is active from the moment the server is provisioned, so it does not have to detect an attack in order to work. There are no opening minutes in which the server is gone. And no null-routing is used: your IP address stays on the network, only the malicious packets are dropped. Whoever takes the IP address off the network achieves the same result for you as the attacker does. The location is Frankfurt am Main.

Advanced DDoS Protection for servers under constant fire

Some servers are not brushed occasionally, they are attacked deliberately and for weeks, often at the same time of day and with changing patterns. For those there is Advanced DDoS Protection from €50.00 per month, PrePaid, with no minimum term and no setup fee. The difference is not more capacity, it is control:

  • A dedicated protected IP from the Frankfurt core, which your server is switched over to inside our own network. Nothing has to be rebuilt on your side.
  • Self-managed protection rules per port and protocol in the customer panel: you define separately what is allowed on 3389 TCP, what on 443 TCP for an RD Gateway and what on your VPN port, and you can close everything else without writing a ticket for it.
  • Changes take effect in real time, so you can fine-tune while an attack is running instead of waiting for a maintenance window.
  • A protection profile that matches the service, including custom applications on any TCP or UDP port.

Advanced DDoS Protection is aimed at KernelHost customers and requires a server at KernelHost. If your Windows server currently runs elsewhere and is regularly under fire there, moving it here is the way forward, because the filtering is part of the network and not an add-on that can be retrofitted onto somebody else's server.

The two tiers compared

Feature Included always-on DDoS protection Advanced DDoS Protection
Price included in every server package, at no surcharge from €50.00 per month, PrePaid
Filtering capacity 17 Tbps of global scrubbing plus Arbor real-time filtering with 3.2 Tbps in Frankfurt am Main the same two-layer filtering
Active from provisioning of the server provisioning of the protected IP
IP address the IP address of your server an additional dedicated protected IP
Rule set automatic profiles, no configuration needed your own rules per port and protocol in the customer panel
Rules for RDP automatic profile for TCP services your own rule set for 3389 TCP, for 443 TCP on an RD Gateway and for the VPN port
Changes are applied automatically take effect in real time, even during an attack
Null-routing no no
Term tied to the server package PrePaid, no minimum term, no notice period, no setup fee

For most Windows servers the included always-on protection together with a clean configuration is enough, meaning NLA, address restriction, UDP 3389 closed and RDP behind a VPN or an RD Gateway. Advanced DDoS Protection is the answer to somebody taking it personally.

What to do during an attack, in this order

The order matters more than the individual steps, because the costliest mistakes happen in the first five minutes.

  1. Determine whether it is the link at all. From outside, test a second service on the same IP address, a web server or a ping. If that is also silent, it is a network problem. If it answers normally and only 3389 hangs, it is an RDP problem.
  2. Measure, do not tinker. First save the values from Get-NetTCPConnection -State SynReceived, Get-NetAdapterStatistics and the count of 4625 events into a file. After the attack those values are gone, and without them nobody can help you.
  3. Do not reboot. A reboot clears all counters and connection states, and the load is back within seconds. You lose exactly the data the filter rules would be built from.
  4. Identify the layer. Many 4625 events mean brute force. Many half-open connections mean a SYN flood. Rising discard counters with a quiet Security log mean volume. The comparison table earlier in this article spells this out in detail.
  5. Set the address restriction, do not stop the service. Restrict the Remote Desktop rules to your own address. That ends brute force and logon floods immediately. Against a volume problem it changes nothing, but it does no harm either.
  6. Close UDP 3389 if it is still open. It takes one line and removes an attack surface from your server and the amplifier role from your IP address, even mid-attack.
  7. Check the management ports. WinRM on 5985, SMB on 445 and everything that does not have to be public belongs restricted to your own address. That reduces the attack surface immediately and without risk to your users.
  8. Bring in your provider with numbers. Open a ticket with five values: time, affected IP address, destination port, measured packet rate and average packet size. Those five decide how quickly the filter rules for your address are adjusted.
  9. Document it afterwards. Record when it started, how long it lasted and which pattern it was. Recurring attacks at the same time of day are the criterion for whether a server needs a dedicated protected IP.

The detailed procedure for a heavy, long running attack is in What to do during a severe DDoS attack, and the server side precautions for Linux systems are in How to protect your server from DDoS attacks.

When you cannot get in yourself any more

This is the case you have to have prepared for, because you cannot prepare once you are in it. Three paths remain, in this order:

First, the VNC console in the customer panel. It does not depend on the guest system's network and therefore works with a saturated link, a broken firewall rule or a crashed RDP service. From there you revert a wrong rule or import the saved rule set with netsh advfirewall import.

Second, if only the account is locked, waiting helps. Windows unlocks by itself once the lockout duration expires. And because the lockout behavior explicitly affects network logons only, according to Microsoft, you can get in over the console in the meantime. The complete procedure is in Fix the RDP account locked out error.

Third, the emergency contact at your provider. When the link is full, the ticket system is faster than another attempt to connect. Give the five values from step 8, even if you only have some of them.

Before you arm a firewall rule, put a small script in place that reverts the address restriction after ten minutes. A scheduled task running Set-NetFirewallRule -Group '@FirewallAPI.dll,-28752' -RemoteAddress Any costs five minutes of preparation and saves the evening. Once the new connection works, delete the task again.

Common mistakes and how to fix them

"Event Viewer is full of 4625, so I am being DDoSed": no, you are being guessed at. A volumetric attack produces not a single 4625 event, because no packet reaches the logon. Many failed logons mean the opposite: your server is reachable and somebody is guessing passwords. The right answer is account lockout and address restriction, not more bandwidth.

"I set SynAttackProtect and nothing improved": the value has had no effect since Windows Vista and Windows Server 2008. SYN attack protection is built in, enabled by default, cannot be disabled, and calculates its thresholds dynamically from CPU cores and memory. There is no switch for it, neither in the registry nor through netsh. Delete the value again so you do not rely on it later.

"I restricted RDP to my IP address and attack traffic still arrives": check with Get-NetFirewallPortFilter | Where-Object { $_.LocalPort -eq 3389 } | Get-NetFirewallRule whether a second, open rule exists. Provider images and installers like to create them. Allow rules are evaluated together, and the widest one wins.

"After the port change I cannot get in any more": the built in Remote Desktop rules are bound to 3389 and do not apply to the new port. Create your own rule for the new port before you reconfigure the service. The full procedure is in Change the RDP port without restarting.

"My account is constantly locked although I have the right password": then somebody is keeping the lockout alive by sending wrong passwords on a schedule. That is a denial of service with minimal effort. The fix is not to disable the lockout, it is to take the service off the internet so the attacker never reaches the logon prompt.

"The firewall should rate limit connections": it cannot. Windows Firewall has no per source rate limiting, neither in the interface nor through netsh or PowerShell. What it can do is allow, block and restrict by address. Genuine rate limiting for RDP exists only in the filtering in front of the server.

"My previous provider blocked my IP address": that is null-routing. The provider is protecting its own network with it. For you the result is identical to a successful attack, usually for hours afterwards. When in doubt, ask whether traffic is filtered or null-routed. The answer decides more about your availability than any hardware specification.

"I see nothing unusual in a capture on the server": if the traffic is already filtered in the network in front, nothing arrives on the server, as expected. That is the normal case with working filtering and not a sign that nothing happened.

In short

  • RDP listens on 3389 TCP by default and, since RDP 8.0, on 3389 UDP as well. An RD Gateway instead accepts 443 TCP and optionally 3391 UDP. The gateway path is the intended route from outside, not an exposed 3389.
  • What looks like a DDoS attack in the Windows event logs is usually brute force. A volumetric attack leaves no trace at all in the Security log, because no packet reaches the logon.
  • The fastest distinction takes ten seconds: if other services on the same IP address are gone too, it is the link. If only 3389 hangs, it is RDP.
  • The registry values SynAttackProtect, TcpMaxHalfOpen and the AFD dynamic backlog values have had no effect since Windows Vista and Windows Server 2008. SYN attack protection is built in, cannot be disabled and calculates its thresholds dynamically from CPU cores and available memory.
  • Windows does not report when that protection kicks in. It is measurable only indirectly, through the number of connections in state SynReceived and the discard counters of the network adapter.
  • Close UDP port 3389 if you do not need the accelerated transport. According to NETSCOUT, RDP can be abused over it as an amplifier at a ratio of 85.9 to 1, and the attacks observed ranged from 20 to 750 Gbps.
  • Moving off port 3389 cuts scanner noise considerably and protects against nothing. Against a volumetric attack it does nothing at all, because such an attack targets the IP address rather than a port number.
  • An account lockout is highly effective against brute force and is itself a target: anyone who knows your username keeps the account locked on a few kilobits per second. According to Microsoft the lockout affects network logons only, so the console stays reachable.
  • The best measure is not to expose RDP at all. A VPN in front of it or an RD Gateway turns the RDP problem into a VPN problem, and that is the smaller one.
  • Above the bandwidth of your link, only filtering in the network in front of the server decides the outcome. At KernelHost that filtering is two-layered, permanently active, without null-routing and included in every server package at no surcharge: 17 Tbps of mitigation capacity in the global scrubbing network plus Arbor real-time filtering with 3.2 Tbps in Frankfurt am Main.

How to set up a Windows server cleanly, from licensing through firewall profiles to hardening RDP, is covered in Set up Windows Server on a VPS. Which size fits which purpose is sorted out in What is a Windows VPS used for.

If your server already runs at KernelHost, the filtering is active without you doing anything. If you still notice something unusual, open a support ticket with the five values from step 8, so the filter rules for your IP address can be adjusted. During an ongoing attack you can also reach us through the WhatsApp emergency chat at +43 650 8209883.

Frequently asked questions

Is my RDP server under attack or just being guessed at?
The distinction takes ten seconds. From outside, test a second service on the same IP address. If that is silent too, the link is the problem, which means a volumetric DDoS attack. If it answers normally and only port 3389 hangs, it is an RDP problem. The second look goes into the Security log: very many events with ID 4625 mean brute force, meaning password guessing against a reachable server. A volumetric attack produces not a single 4625 event, because no packet reaches the logon.
Which ports does RDP use and which of them need to face the internet?
RDP listens on port 3389 TCP by default, and since RDP 8.0 on port 3389 UDP as an accelerated transport. Microsoft lists both together as the standard port of Remote Desktop Services. A Remote Desktop Gateway instead accepts 443 TCP, optionally with 3391 UDP. Internally, depending on the role, 5504 TCP for the connection broker, 5985 TCP for administration and the RPC ports of the licensing server are added. For access from outside, the gateway path over 443 is the intended one, not an exposed port 3389.
What is a SYN flood against port 3389 and what does Windows do about it?
In a SYN flood the attacker sends TCP packets with the SYN bit set and a forged source address. For each one the server creates a half-open connection entry, answers, and waits for a third packet that never comes. Windows has had built in SYN attack protection since Windows Vista and Windows Server 2008. It is enabled by default, cannot be disabled, and calculates its thresholds dynamically from the number of CPU cores and the available memory. Once it engages, new connections run into timeouts while existing sessions keep running.
Does the SynAttackProtect registry value help against SYN floods?
No. SynAttackProtect, TcpMaxHalfOpen, TcpMaxHalfOpenRetried and TcpMaxConnectResponseRetransmissions under Services\Tcpip\Parameters have had no effect since Windows Vista and Windows Server 2008. The AFD values EnableDynamicBacklog, MinimumDynamicBacklog, MaximumDynamicBacklog and DynamicBacklogGrowthDelta were even removed from the driver. Microsoft deliberately exposes no configurable parameters, neither in the registry nor through netsh, because the protection calculates its own thresholds. Setting these values accomplishes nothing and is harmful, because afterwards you believe you are protected.
Is it worth changing the RDP port from 3389 to something else?
Against automated scanners yes, against a determined attacker no, against DDoS not at all. The bulk of bots checks port 3389 only and stops finding you afterwards, which cuts the number of failed logons by orders of magnitude and makes Event Viewer readable again. A full port scan takes seconds, however, and search engines for exposed services recognize RDP by its protocol fingerprint regardless of the port. A volumetric attack targets your IP address anyway, not a port number.
Can my RDP server be abused for DDoS attacks against others?
Yes, if port 3389 UDP is exposed to the internet. In January 2021 NETSCOUT described how the RDP service on UDP/3389 can be abused as an amplifier at a ratio of 85.9 to 1. The resulting reply packets are consistently 1,260 bytes long and padded with zeroes. Around 33,000 abusable servers were counted, and the attacks observed with them ranged from about 20 to 750 Gbps. Block UDP 3389 if you do not need the accelerated transport. RDP falls back to TCP automatically.
How do I restrict RDP to specific IP addresses?
Through Windows Firewall, using the language neutral group identifier so that it works on English and German systems alike. The command is Set-NetFirewallRule -Group '@FirewallAPI.dll,-28752' -RemoteAddress followed by your address list. Verify the result with Get-NetFirewallAddressFilter. The second step matters: check with Get-NetFirewallPortFilter whether a second, wider rule for port 3389 exists. Provider images often create them, and allow rules are evaluated together, so the widest one wins.
Can Windows Firewall rate limit connections per source address?
No. Windows Firewall has no rate limiting at all, neither through the graphical interface nor through netsh advfirewall or the PowerShell cmdlets. It can allow, block and restrict by address range, profile, program and service, and that is all. Against a connection flood only two tools remain on the server: restricting to known source addresses, and a hard cap on concurrent sessions through Group Policy. Genuine rate limiting for RDP exists only in the filtering in the network in front of the server.
Does an account lockout policy protect against DDoS attacks?
No, it protects against brute force, and for that it is the most effective single measure. Against overload it does nothing, because a volumetric attack never reaches the logon. Worse, it is a target itself. Anyone who knows your username keeps the account permanently locked by sending wrong passwords on a schedule, which costs a few kilobits per second. According to Microsoft, however, the lockout behavior affects network logons such as RDP only: over a console you can still get in during the lockout period.
Should I put RDP behind a VPN or behind an RD Gateway?
Both are right, the choice depends on the environment. For a single Windows VPS with a handful of people needing access, a VPN is the shorter route: you allow RDP only for the VPN address range and close port 3389 on the internet. For an environment with several session hosts, a Remote Desktop Gateway on 443 TCP is the cleaner structure, because Windows clients need no additional service. What both share is the decisive part: port 3389 has disappeared from the internet afterwards.
How do I recognize a DDoS attack in Event Viewer?
You do not, and that is the real answer. A volumetric attack leaves no trace in the Security log, because no packet reaches the logon. What you see there are logon attempts: event 4625 for failed logons, 4624 with logon type 10 for successful Remote Desktop logons, and 4740 for an account lockout. In the RemoteDesktopServices-RdpCoreTS log, event 131 records every accepted connection and event 140 records a logon failure, the latter only for a username that does not exist on the system.
How do I measure on Windows whether a SYN flood is running?
With three commands in an elevated PowerShell session. Get-NetTCPConnection -State SynReceived counts the half-open connections: two digits is normal, four or five digits is a SYN flood. Get-NetAdapterStatistics returns ReceivedBytes, ReceivedUnicastPackets and ReceivedDiscardedPackets with language neutral property names, unlike the localized counter paths used by Get-Counter. And Get-NetTCPConnection -LocalPort 3389 -State Established shows how many sessions are really up. Measure these once during normal operation, otherwise you have no baseline in an emergency.
What do I do if I cannot reach the server myself any more?
Use a console that does not depend on the network. On KVM servers from KernelHost the customer panel offers a VNC console that looks directly at the screen of the virtual machine and keeps working with a saturated link, a wrong firewall rule or a crashed RDP service. From there you revert the rule or import a previously saved rule set with netsh advfirewall import. Export it beforehand with netsh advfirewall export. If only the account is locked, Windows unlocks it by itself once the lockout duration expires.
Will my Windows server at KernelHost go offline during an attack?
No. No null-routing is used: your IP address stays on the network, only the malicious packets are dropped. The protection is built in two layers, with 17 Tbps of mitigation capacity in the global scrubbing network and Arbor real-time filtering with 3.2 Tbps in Frankfurt am Main. It runs permanently and is active from the moment the server is provisioned, so it does not have to detect an attack first. For RDP that means SYN floods and connection floods against 3389 TCP end there, not on your network card.
What does DDoS protection cost at KernelHost and when do I need Advanced DDoS Protection?
The two-layer always-on protection is included in every server package at no surcharge and active from provisioning. You neither order it nor switch it on. You need Advanced DDoS Protection when your server is not brushed occasionally but attacked deliberately and for weeks, and you want to steer the filtering yourself. You get a dedicated protected IP and manage the rules per port and protocol yourself in the customer panel, with changes taking effect in real time. Pricing starts at €50.00 per month, PrePaid, with no minimum term and no setup fee.

RDP RDP DDoS protection Port 3389 Windows Server SYN flood Brute force Windows Firewall Advanced DDoS Protection