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.
Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' |
Select-Object UserAuthentication, PortNumber, SecurityLayer, MinEncryptionLevelUserAuthentication = 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:
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 3SecurityLayer = 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.
Get-LocalGroupMember -Group 'Remote Desktop Users'
Get-LocalUser | Where-Object Enabled -eq $true | Select-Object Name, LastLogonThen tighten the logon rules:
net accounts /lockoutthreshold:5 /lockoutduration:15 /lockoutwindow:15Five 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:
New-ItemProperty 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services' `
-Name fSingleSessionPerUser -PropertyType DWord -Value 1 -ForceSet 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.
$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 -ForceValues 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:
qwinsta
quserqwinsta 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.
logoff 3
tsdiscon 3logoff 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:
auditpol /set /subcategory:"Logon" /success:enable /failure:enable
auditpol /set /subcategory:"Logoff" /success:enableFailed 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
- Reconnect from your client to
203.0.113.10:3389. With NLA on, you should be asked for credentials before the desktop appears. - Run
qwinstaand confirm your session shows asActivewith the expected user. - Leave a test session idle past your
MaxIdleTimevalue and confirm it disconnects. - Enter a wrong password five times on a test account and confirm the lockout triggers.
- 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 to0if 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.
logoffreports access denied. You are not running PowerShell as Administrator, or the session belongs to a system account that must not be ended.
Next steps
- Secure Remote Desktop on Windows Server for the wider hardening checklist.
- View or control another user's RDP session (shadowing) when you need to help someone without taking over their logon.
- Windows RDP session persistence and roaming profiles if users need their settings to follow them between sessions.
