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

Source: https://srvscripts.com/guides/rdp-connection-logs-event-ids/
Updated: 2026-10-07
Publisher: srvScripts (https://srvscripts.com/)

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.

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

## The RDP connection logs at a glance

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 ID | Log | Meaning | Key fields |
| --- | --- | --- | --- |
| 1149 | TerminalServices-RemoteConnectionManager/Operational | “Remote Desktop Services: User authentication succeeded” (network-level connection accepted) | User, Domain, Source Network Address |
| 4624 | Security | An account was successfully logged on | TargetUserName, LogonType, IpAddress, TargetLogonId |
| 4625 | Security | An account failed to log on | TargetUserName, LogonType, IpAddress, Status, SubStatus |
| 21 | TerminalServices-LocalSessionManager/Operational | Session logon succeeded | User, Session ID, Source Network Address |
| 22 | LocalSessionManager/Operational | Shell start notification received (desktop loaded) | User, Session ID |
| 23 | LocalSessionManager/Operational | Session logoff succeeded | User, Session ID |
| 24 | LocalSessionManager/Operational | Session has been disconnected | User, Session ID, Source Network Address |
| 25 | LocalSessionManager/Operational | Session reconnection succeeded | User, Session ID, Source Network Address |
| 39 | LocalSessionManager/Operational | Session X has been disconnected by session Y | Target and source session IDs |
| 40 | LocalSessionManager/Operational | Session X has been disconnected, reason code Z | Session ID, reason code |
| 4778 | Security | A session was reconnected to a Window Station | Account, ClientName, ClientAddress |
| 4779 | Security | A session was disconnected from a Window Station | Account, ClientName, ClientAddress |
| 4647 | Security | User initiated logoff | TargetUserName, TargetLogonId |
| 4634 | Security | An 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.

- Create or edit a GPO linked to the servers (and a separate one for workstations if you allow RDP to them).

- Go to `Computer Configuration » Policies » Windows Settings » Security Settings » Advanced Audit Policy Configuration » Audit Policies » Logon/Logoff`.

- Configure **Audit Logon** for Success and Failure, **Audit Logoff** for Success, and **Audit Other Logon/Logoff Events** for Success and Failure.

- 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

| LogonType | Name | When you see it with RDP |
| --- | --- | --- |
| 10 | RemoteInteractive | A new Remote Desktop session logon |
| 7 | Unlock | Unlocking a session; a reconnect to an existing disconnected session can also be recorded this way |
| 3 | Network | The Network Level Authentication step before the session is built. Failed NLA logons appear as 4625 type 3, not type 10 |
| 12 | CachedRemoteInteractive | Microsoft 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 SubStatus | Meaning | What it suggests |
| --- | --- | --- |
| 0xC000006A | Correct user name, wrong password | Typo or a password-guessing attack on a real account |
| 0xC0000064 | User name does not exist | Dictionary attack with guessed names |
| 0xC000006D | Bad user name or authentication information (general) | Check SubStatus for the detail |
| 0xC0000234 | Account locked out | Lockout threshold reached |
| 0xC0000072 | Account disabled | Leaver account still in use somewhere |
| 0xC000015B | Logon type not granted | User not allowed “Allow log on through Remote Desktop Services” |
| 0xC0000193 | Account expired | Contractor 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 code | Meaning |
| --- | --- |
| 0 | No additional information (often a network drop or the client closed) |
| 3 | Server idle time-out reached |
| 4 | Logon time-out reached |
| 5 | Connection replaced by another connection |
| 11 | User activity initiated the disconnect (the user clicked Disconnect or closed the window) |
| 12 | The 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:

- Remove direct internet exposure of TCP 3389. Publish Remote Desktop through an RD Gateway or VPN with multifactor authentication.

- 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.

- Limit **“Allow log on through Remote Desktop Services”** to a dedicated group rather than all users.

- 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:

- Open `eventvwr.msc`, right-click **Custom Views** and choose **Create Custom View**.

- Switch to the **XML** tab, tick **Edit query manually** and paste the query below.

- Name the view RDP sessions. It now lists connections, logons, disconnects and failures in time order.

```

    *[System[(EventID=1149)]]
    *[System[(EventID=21 or EventID=23 or EventID=24 or EventID=25 or EventID=39 or EventID=40)]]
    *[System[(EventID=4624 or EventID=4625)]] and *[EventData[Data[@Name='LogonType']='10']]

```

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:104857600wevtutil sl "Microsoft-Windows-TerminalServices-LocalSessionManager/Operational" /ms:104857600wevtutil 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

| Symptom | Likely cause | Fix |
| --- | --- | --- |
| No 4624 or 4625 events at all | Audit Logon not enabled, or legacy audit settings override subcategories | Enable the subcategories and the “Force audit policy subcategory settings” option; check auditpol /get |
| Every source IP is the same internal address | Connections arrive through RD Gateway, a load balancer or NAT | Read the gateway’s log for the real client IP |
| Failed RDP logons appear as type 3 | Network Level Authentication checks the password before the session starts | Include 4625 type 3 in RDP failure searches |
| Old sessions missing from the report | Logs overwritten | Increase log sizes or forward events |
| 1149 present but no event 21 | User 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](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4624), [4625(F): An account failed to log on](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4625), [ExtendedDisconnectReasonCode enumeration](https://learn.microsoft.com/en-us/windows/win32/termserv/extendeddisconnectreasoncode).

**Related guides:** [AD Account Lockout Source: Easy Event 4740 Tracing](/guides/ad-account-lockout-source-event-4740/) · [AD audit policy: logons, account changes, lockouts](/guides/active-directory-audit-policy/) · [Enable Remote Desktop Group Policy and Firewall Rules Made Easy](/guides/enable-remote-desktop-group-policy/).

**See also:** [Event ID 4625: An Account Failed to Log On (Status Codes)](/guides/event-id-4625-failed-logon/)

## 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.
