Security

Windows Server: Securing Remote Desktop Session Management (RDP) Best Practices

Lock down Remote Desktop session management on Windows Server — require Network Level Authentication, cap idle and disconnected sessions, audit logons and end sessions you do not recognise.

IntermediateWindows server6 min read

Secure RDP session management means controlling three things: who is allowed to open a session, how long a session may sit idle or disconnected, and how you notice and end sessions you did not start. Get those right and session hijacking, forgotten logged-in desktops and brute-force logons stop being a real risk. This guide walks through the settings on Windows Server 2019 through 2025, on a Windows VPS or Admin RDP.

Before you start

You need:

  • A Windows VPS or Admin RDP plan with Administrator access. Connect as 203.0.113.10:3389 — Remote Desktop uses TCP port 3389 by default.
  • An elevated PowerShell window on the server (right-click PowerShell, Run as administrator).
  • A second way in, in case you lock yourself out: the browser console in your VPS provider's control panel works even when RDP does not.
  • A note of the current values before you change them. Group Policy settings apply to every user on the machine.

Warning: Restarting the TermService service or rebooting the server drops every active RDP session, including yours. Do it at a time when nobody else is working.

Harden the RDP listener and authentication

Start by checking what the listener is doing now.

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

UserAuthentication = 1 means Network Level Authentication (NLA) is on. NLA forces the client to authenticate before a session is created, which blocks most pre-authentication attacks and stops unauthenticated sessions from consuming resources. If it is 0, turn it on:

PowerShell
Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' `
  -Name UserAuthentication -Value 1
Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' `
  -Name SecurityLayer -Value 2
Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' `
  -Name MinEncryptionLevel -Value 3

SecurityLayer = 2 requires TLS for the connection and MinEncryptionLevel = 3 enforces high encryption. Confirm PortNumber is 3389; if it is not, see restore Remote Desktop to port 3389 before you change anything else.

Control who can hold a session

Every account in the local Remote Desktop Users group can open a session. Audit that list and remove anything you do not recognise.

PowerShell
Get-LocalGroupMember -Group 'Remote Desktop Users'
Get-LocalUser | Where-Object Enabled -eq $true | Select-Object Name, LastLogon

Then tighten the logon rules:

CMD
net accounts /lockoutthreshold:5 /lockoutduration:15 /lockoutwindow:15

Five failed attempts locks the account for fifteen minutes. That is enough to make password guessing impractical without locking out real users constantly. If you need to add or remove people, follow create Windows users with Remote Desktop access.

To stop one account holding several sessions at once — a common way a stolen credential goes unnoticed — set one session per user:

PowerShell
New-ItemProperty 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services' `
  -Name fSingleSessionPerUser -PropertyType DWord -Value 1 -Force

Set idle and disconnected session limits

A disconnected session stays alive on the server with the user's desktop, files and open applications in memory. If someone walks away from an unlocked laptop, that session is a way in. Cap it.

PowerShell
$ts = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services'
New-Item $ts -Force | Out-Null
New-ItemProperty $ts -Name MaxIdleTime -PropertyType DWord -Value 900000 -Force
New-ItemProperty $ts -Name MaxDisconnectionTime -PropertyType DWord -Value 60000 -Force
New-ItemProperty $ts -Name MaxConnectionTime -PropertyType DWord -Value 0 -Force
New-ItemProperty $ts -Name fResetBroken -PropertyType DWord -Value 1 -Force

Values are milliseconds: 900000 is 15 minutes idle, 60000 is one minute after disconnect, and 0 for MaxConnectionTime means no absolute session length. fResetBroken = 1 means a session that hits a limit is reset rather than left in a broken state.

Warning: These limits end sessions and close unsaved work. Tell your users before you apply them, and check the values suit long-running jobs such as builds or file copies. Stop Remote Desktop sessions ending when idle or disconnected covers the trade-offs in more detail.

Audit sessions and end the ones you did not start

List what is running right now:

CMD
qwinsta
quser

qwinsta shows the session ID, the user, the state (Active, Disc, Listen) and whether it is the console session. If you see an account you cannot explain, check it before you act — a colleague may simply be working.

CMD
logoff 3
tsdiscon 3

logoff 3 ends session 3 and closes its applications. tsdiscon 3 disconnects it but leaves the desktop running, which is the gentler option when you only want to free the connection.

Warning: Logging off another user's session destroys unsaved work in that session. Disconnect first if you are unsure.

Turn on logon auditing so you have a record:

CMD
auditpol /set /subcategory:"Logon" /success:enable /failure:enable
auditpol /set /subcategory:"Logoff" /success:enable

Failed logons appear in Event Viewer under Windows Logs > Security as event 4625, successful ones as 4624, and session connect/disconnect as 4778 and 4779. A burst of 4625 events from one address is the signature of a password-guessing attempt.

Check it works

  1. Reconnect from your client to 203.0.113.10:3389. With NLA on, you should be asked for credentials before the desktop appears.
  2. Run qwinsta and confirm your session shows as Active with the expected user.
  3. Leave a test session idle past your MaxIdleTime value and confirm it disconnects.
  4. Enter a wrong password five times on a test account and confirm the lockout triggers.
  5. Open Event Viewer and confirm 4624 and 4625 entries are being written.

Troubleshooting

  • "The connection was denied because the user account is not authorized for remote login." The account is not in the Remote Desktop Users group. Add it with Add-LocalGroupMember -Group 'Remote Desktop Users' -Member 'deploy'.
  • Clients fail immediately after you enable NLA. Older or third-party RDP clients may not support it. Update the client, or check fix "Your credentials did not work" in Remote Desktop.
  • Sessions end after fifteen minutes of no typing. That is MaxIdleTime. Raise it, or set it to 0 if you genuinely need unlimited idle sessions.
  • You locked yourself out with the lockout policy. Wait out the lockout window, or sign in through the browser console in your VPS provider's control panel and reset the account.
  • logoff reports access denied. You are not running PowerShell as Administrator, or the session belongs to a system account that must not be ended.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.