Emergency server help: get in touch

RDP Connection Logs: 14 Event IDs to Track Who Connected and From Where

Find out who connected over Remote Desktop, from which IP address and for how long, using the RemoteConnectionManager, LocalSessionManager and Security event logs, with the audit policies they need, a PowerShell report and brute-force detection.

Published Updated 12 min read

RDP connection logs on Windows Server 2025 and Windows 11 are spread across three event logs, and you need all three to answer who connected, from which IP address, when the session started and how it ended. This guide lists the 14 event IDs that matter, the audit policies that must be on, a PowerShell script that turns them into a report with source IPs, a brute-force check and the settings that keep the evidence long enough.

Short answer: Successful network authentication for Remote Desktop is event 1149 in Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational (user and source IP). The actual logon is Security event 4624 with Logon Type 10 (RemoteInteractive), failures are 4625, and session logon, disconnect and reconnect are events 21, 24 and 25 in Microsoft-Windows-TerminalServices-LocalSessionManager/Operational. Enable Audit Logon, Audit Logoff and Audit Other Logon/Logoff Events so the Security events are written.

The RDP connection logs at a glance

RDP Connection Logs summary card: Successful network authentication for Remote Desktop is event 1149 in…
In short: Successful network authentication for Remote Desktop is event 1149 in Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational (user and source IP).

A Remote Desktop connection passes through several components, and each writes its own record. Read the table from top to bottom to follow one session.

Event IDLogMeaningKey fields
1149TerminalServices-RemoteConnectionManager/Operational“Remote Desktop Services: User authentication succeeded” (network-level connection accepted)User, Domain, Source Network Address
4624SecurityAn account was successfully logged onTargetUserName, LogonType, IpAddress, TargetLogonId
4625SecurityAn account failed to log onTargetUserName, LogonType, IpAddress, Status, SubStatus
21TerminalServices-LocalSessionManager/OperationalSession logon succeededUser, Session ID, Source Network Address
22LocalSessionManager/OperationalShell start notification received (desktop loaded)User, Session ID
23LocalSessionManager/OperationalSession logoff succeededUser, Session ID
24LocalSessionManager/OperationalSession has been disconnectedUser, Session ID, Source Network Address
25LocalSessionManager/OperationalSession reconnection succeededUser, Session ID, Source Network Address
39LocalSessionManager/OperationalSession X has been disconnected by session YTarget and source session IDs
40LocalSessionManager/OperationalSession X has been disconnected, reason code ZSession ID, reason code
4778SecurityA session was reconnected to a Window StationAccount, ClientName, ClientAddress
4779SecurityA session was disconnected from a Window StationAccount, ClientName, ClientAddress
4647SecurityUser initiated logoffTargetUserName, TargetLogonId
4634SecurityAn account was logged off (session ended)TargetUserName, LogonType, TargetLogonId

The full path of the two Terminal Services logs in Event Viewer is Applications and Services Logs » Microsoft » Windows » TerminalServices-RemoteConnectionManager » Operational and ... » TerminalServices-LocalSessionManager » Operational. They are enabled by default. The Security events depend on the audit policy.

Prerequisites: enable the audit policies

Without the right audit subcategories, your RDP connection logs will have gaps: 1149 and 21-25 still appear, but 4624, 4625, 4778 and 4779 do not.

  1. Create or edit a GPO linked to the servers (and a separate one for workstations if you allow RDP to them).
  2. Go to Computer Configuration » Policies » Windows Settings » Security Settings » Advanced Audit Policy Configuration » Audit Policies » Logon/Logoff.
  3. Configure Audit Logon for Success and Failure, Audit Logoff for Success, and Audit Other Logon/Logoff Events for Success and Failure.
  4. Under Security Settings » Local Policies » Security Options, enable “Audit: Force audit policy subcategory settings (Windows Vista or later) to override audit policy category settings” so legacy category settings cannot override these subcategories.

Check or set the result locally with auditpol:

auditpol /get /category:"Logon/Logoff"
auditpol /set /subcategory:"Logon" /success:enable /failure:enable
auditpol /set /subcategory:"Logoff" /success:enable
auditpol /set /subcategory:"Other Logon/Logoff Events" /success:enable /failure:enable

Use auditpol for testing only. On domain members, the GPO is the source of truth and will overwrite local changes at the next refresh.

Event 1149: who reached the server

Event 1149 is written by the Remote Connection Manager when a client completes network authentication. Its text reads “Remote Desktop Services: User authentication succeeded”, followed by the user name, domain and source network address. It is the quickest way to list RDP source IPs, but read it carefully:

  • With Network Level Authentication (the default), 1149 means the credentials were accepted, not that a desktop was ever created. A user who closes the window at a warning still leaves a 1149.
  • It records the address the server sees. Behind an RD Gateway or a NAT device, that is the gateway or NAT address, not the client’s own IP.
  • Failed attempts do not appear in this log. Use 4625 for those.

Events 4624 and 4625: successful and failed logons

Logon types that matter for RDP

LogonTypeNameWhen you see it with RDP
10RemoteInteractiveA new Remote Desktop session logon
7UnlockUnlocking a session; a reconnect to an existing disconnected session can also be recorded this way
3NetworkThe Network Level Authentication step before the session is built. Failed NLA logons appear as 4625 type 3, not type 10
12CachedRemoteInteractiveMicrosoft describes it as the same as RemoteInteractive, used for internal auditing

Filter for types 10 and 7 to count real sessions, and for 4625 with types 3 and 10 to catch failed RDP attempts. The IpAddress field holds the client address; WorkstationName holds the client’s computer name when the client supplied one. TargetLogonId lets you tie a 4624 to its later 4634 logoff.

4625 status codes

Status or SubStatusMeaningWhat it suggests
0xC000006ACorrect user name, wrong passwordTypo or a password-guessing attack on a real account
0xC0000064User name does not existDictionary attack with guessed names
0xC000006DBad user name or authentication information (general)Check SubStatus for the detail
0xC0000234Account locked outLockout threshold reached
0xC0000072Account disabledLeaver account still in use somewhere
0xC000015BLogon type not grantedUser not allowed “Allow log on through Remote Desktop Services”
0xC0000193Account expiredContractor account past its end date

Logoff, disconnect and reconnect events

  • 4647 is logged when the user chooses Sign out. 4634 follows when the logon session is actually destroyed. If a session is ended by a time limit or by an administrator, expect 4634 without a preceding 4647.
  • 4779 (session disconnected) and 4778 (session reconnected) come from Audit Other Logon/Logoff Events and include ClientName and ClientAddress, so they show where a user reconnected from, which may differ from where the session started.
  • In LocalSessionManager, 24 is a disconnect and 25 a reconnect, both with the source address. 23 marks the logoff.

Events 39 and 40: why a session disconnected

Event 39 appears when one session disconnects another, for example when the same user signs in again from a different PC and takes over the session. Event 40 includes a reason code. The codes follow the ExtendedDisconnectReasonCode values Microsoft documents for Remote Desktop:

Reason codeMeaning
0No additional information (often a network drop or the client closed)
3Server idle time-out reached
4Logon time-out reached
5Connection replaced by another connection
11User activity initiated the disconnect (the user clicked Disconnect or closed the window)
12The user logged off

PowerShell: build an RDP connection report

This script reads the last seven days of RDP connection logs on the local server and writes one CSV with time, event, user, logon type and source IP. Run it elevated, because the Security log needs administrator rights.

$since = (Get-Date).AddDays(-7)
function Get-EventFields($e) {
  $h = @{}
  $x = [xml]$e.ToXml()
  foreach ($d in $x.Event.EventData.Data) { $h[$d.Name] = $d.'#text' }
  if ($x.Event.UserData) { foreach ($n in $x.Event.UserData.FirstChild.ChildNodes) { $h[$n.Name] = $n.InnerText } }
  $h
}
$rows = @()
$rcm = @{ LogName = 'Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational'; Id = 1149; StartTime = $since }
foreach ($e in Get-WinEvent -FilterHashtable $rcm -ErrorAction SilentlyContinue) {
  $p = $e.Properties
  $rows += [pscustomobject]@{ Time = $e.TimeCreated; Event = 1149; User = "$($p[1].Value)\$($p[0].Value)"; LogonType = ''; SourceIP = $p[2].Value }
}
$lsm = @{ LogName = 'Microsoft-Windows-TerminalServices-LocalSessionManager/Operational'; Id = 21,23,24,25; StartTime = $since }
foreach ($e in Get-WinEvent -FilterHashtable $lsm -ErrorAction SilentlyContinue) {
  $f = Get-EventFields $e
  $rows += [pscustomobject]@{ Time = $e.TimeCreated; Event = $e.Id; User = $f.User; LogonType = ''; SourceIP = $f.Address }
}
$sec = @{ LogName = 'Security'; Id = 4624,4625; StartTime = $since }
foreach ($e in Get-WinEvent -FilterHashtable $sec -ErrorAction SilentlyContinue) {
  $f = Get-EventFields $e
  if ($f.LogonType -in '10','7' -or ($e.Id -eq 4625 -and $f.LogonType -eq '3')) {
    $rows += [pscustomobject]@{ Time = $e.TimeCreated; Event = $e.Id; User = "$($f.TargetDomainName)\$($f.TargetUserName)"; LogonType = $f.LogonType; SourceIP = $f.IpAddress }
  }
}
$rows | Sort-Object Time | Export-Csv C:\Temp\rdp-report.csv -NoTypeInformation
$rows | Where-Object Event -eq 4624 | Group-Object SourceIP | Sort-Object Count -Descending | Select-Object Count, Name

On a busy server the Security query is the slow part. Narrow $since, or run the script against a remote host with Get-WinEvent -ComputerName added to each query. Note that type 3 logons from ordinary file share access can also fail, so treat 4625 type 3 rows as RDP only when the server does not serve files.

Detect RDP brute-force attempts

An exposed RDP port attracts automated password guessing within hours. The pattern in the RDP connection logs is many 4625 events from few IP addresses, usually with SubStatus 0xC0000064 or 0xC000006A and names such as administrator, admin or user.

$hour = @{ LogName = 'Security'; Id = 4625; StartTime = (Get-Date).AddHours(-1) }
Get-WinEvent -FilterHashtable $hour -ErrorAction SilentlyContinue | ForEach-Object {
  $x = [xml]$_.ToXml(); $d = @{}
  foreach ($n in $x.Event.EventData.Data) { $d[$n.Name] = $n.'#text' }
  [pscustomobject]@{ IP = $d.IpAddress; User = $d.TargetUserName; Sub = $d.SubStatus }
} | Group-Object IP | Where-Object Count -gt 20 | Sort-Object Count -Descending |
  Select-Object Count, Name, @{ n = 'Users'; e = { ($_.Group.User | Sort-Object -Unique) -join ', ' } }

What to do with the result:

  1. Remove direct internet exposure of TCP 3389. Publish Remote Desktop through an RD Gateway or VPN with multifactor authentication.
  2. Set an account lockout policy (threshold, duration and reset counter) in the Default Domain Policy or a fine-grained password policy, and watch event 4740 on domain controllers for lockouts.
  3. Limit “Allow log on through Remote Desktop Services” to a dedicated group rather than all users.
  4. Block an attacking address while you fix the exposure:
    New-NetFirewallRule -DisplayName "Block RDP attacker" -Direction Inbound -Protocol TCP -LocalPort 3389 -RemoteAddress 203.0.113.50 -Action Block

If IpAddress is empty or - in some 4625 events, the Security event alone cannot give you the source. Check the RD Gateway log (Microsoft-Windows-TerminalServices-Gateway/Operational) or your firewall logs for the source.

View RDP connection logs in Event Viewer

For a quick look without scripts, build one custom view that combines the three RDP connection logs:

  1. Open eventvwr.msc, right-click Custom Views and choose Create Custom View.
  2. Switch to the XML tab, tick Edit query manually and paste the query below.
  3. Name the view RDP sessions. It now lists connections, logons, disconnects and failures in time order.
<QueryList>
  <Query Id="0">
    <Select Path="Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational">*[System[(EventID=1149)]]</Select>
    <Select Path="Microsoft-Windows-TerminalServices-LocalSessionManager/Operational">*[System[(EventID=21 or EventID=23 or EventID=24 or EventID=25 or EventID=39 or EventID=40)]]</Select>
    <Select Path="Security">*[System[(EventID=4624 or EventID=4625)]] and *[EventData[Data[@Name='LogonType']='10']]</Select>
  </Query>
</QueryList>

Export the view as XML and import it on other servers with Import Custom View. When a user reports “my session was closed”, filter the view to their name and read the events around the time: a 40 with reason 3 points at an idle limit, a 39 or a 40 with reason 5 at a second sign-in, and a 40 with reason 0 usually at a network drop or a closed client.

Query several servers at once

On an RDS farm the same user may land on any Session Host, so collect RDP connection logs from all of them. The simplest way is to wrap the report script in Invoke-Command:

$hosts = "rdsh01","rdsh02","rdsh03"
Invoke-Command -ComputerName $hosts -ScriptBlock {
  Get-WinEvent -FilterHashtable @{ LogName = 'Microsoft-Windows-TerminalServices-LocalSessionManager/Operational'; Id = 21,24,25; StartTime = (Get-Date).AddDays(-1) } -ErrorAction SilentlyContinue |
    Select-Object TimeCreated, Id, Message
} | Sort-Object TimeCreated | Format-Table PSComputerName, TimeCreated, Id -AutoSize

WinRM must be allowed from your admin workstation. For anything longer than a few days of history, forwarded events on a collector are faster than querying each host.

Retention and forwarding

Default log sizes on a busy server keep only days of Security events and even less of the Terminal Services logs. Plan retention before you need the evidence.

  • Security log size: set Computer Configuration » Policies » Administrative Templates » Windows Components » Event Log Service » Security » "Specify the maximum log file size (KB)". 1 to 4 GB is common on RDS hosts.
  • Terminal Services logs: enlarge them with wevtutil:
    wevtutil sl "Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational" /ms:104857600
    wevtutil sl "Microsoft-Windows-TerminalServices-LocalSessionManager/Operational" /ms:104857600
    wevtutil gl "Microsoft-Windows-TerminalServices-LocalSessionManager/Operational"
  • Central collection: forward the events to a collector with Windows Event Forwarding. On the collector run wecutil qc and create a source-initiated subscription for IDs 1149, 21-25, 39, 40, 4624, 4625, 4634, 4647, 4778 and 4779. On the sources, set Windows Components » Event Forwarding » "Configure target Subscription Manager" and add NETWORK SERVICE to the local Event Log Readers group so the Security log can be read. A SIEM agent is the alternative.

Troubleshooting

SymptomLikely causeFix
No 4624 or 4625 events at allAudit Logon not enabled, or legacy audit settings override subcategoriesEnable the subcategories and the “Force audit policy subcategory settings” option; check auditpol /get
Every source IP is the same internal addressConnections arrive through RD Gateway, a load balancer or NATRead the gateway’s log for the real client IP
Failed RDP logons appear as type 3Network Level Authentication checks the password before the session startsInclude 4625 type 3 in RDP failure searches
Old sessions missing from the reportLogs overwrittenIncrease log sizes or forward events
1149 present but no event 21User cancelled after authentication, or logon failed later (licence, profile, rights)Check LocalSessionManager and the Application log at that time

Keep the report script scheduled, review the brute-force summary daily on any host reachable from outside, and keep RDP connection logs for at least as long as your incident response policy requires.

RDP connection logs at a glance

Official documentation: 4624(S): An account was successfully logged on, 4625(F): An account failed to log on, ExtendedDisconnectReasonCode enumeration.

Related guides: AD Account Lockout Source: Easy Event 4740 Tracing · AD audit policy: logons, account changes, lockouts · Enable Remote Desktop Group Policy and Firewall Rules Made Easy.

See also: Event ID 4625: An Account Failed to Log On (Status Codes)

Frequently asked questions

Which event ID shows an RDP logon?

Security event 4624 with Logon Type 10 records a Remote Desktop logon, and a reconnect can appear as type 7. Event 1149 in the RemoteConnectionManager log and event 21 in the LocalSessionManager log confirm the connection and the session start.

Where can I find the IP address of an RDP connection?

Event 1149 shows the Source Network Address, 4624 and 4625 have the IpAddress field, and LocalSessionManager events 21, 24 and 25 include the source address. Behind an RD Gateway or NAT these show the gateway or NAT address.

Why do failed RDP logons show Logon Type 3?

With Network Level Authentication the password is checked through a network logon before the session is created, so failures are recorded as 4625 with Logon Type 3.

What does event 40 reason code 5 mean?

Reason code 5 means the client’s connection was replaced by another connection, usually because the same user signed in again from another device.

Which audit policies are needed for RDP logon events?

Enable Audit Logon for Success and Failure, Audit Logoff for Success and Audit Other Logon/Logoff Events for Success and Failure under Advanced Audit Policy Configuration.

Free website test

Is your website set up right?

Check SSL, security headers, redirects, robots.txt, sitemap, llms.txt and security.txt in one test. It takes about 30 seconds.