Microsoft Entra ID security

How to find failed sign-ins in Microsoft Entra ID

List failed sign-in attempts with Microsoft Graph PowerShell, filter the sign-in logs by failure in the Entra admin centre, or run Altivane's Failed Sign-Ins report for the accounts failing most.

By the Published

To find failed sign-ins in Microsoft Entra ID, read the sign-in logs and keep the entries whose error code is not 0, then group them by account to see who fails most. Reading the logs through Microsoft Graph needs Microsoft Entra ID P1 or P2. Entra keeps sign-ins for 30 days with P1 or P2 and 7 days without, so a failure older than that is gone unless the logs were archived.

Choose the method that fits the job
MethodBest fit
PowerShellA CSV of every failure in the days you choose, and a second of the accounts with the most.
Admin centreLooking into 1 failure: its error code, its reason and the Conditional Access result.
AltivaneRecommended for weekly reviews, with each account's failures counted beside its usual reason.

Before you start

Use an account with a role that can read the sign-in logs. Reports Reader is the least privileged; Global Reader, Security Reader, Security Operator and Security Administrator work too. Reading the logs with Microsoft Graph needs Microsoft Entra ID P1 or P2, while the admin centre shows them on every edition. The PowerShell example requests AuditLog.Read.All; your organisation may require administrator consent.

Microsoft Graph returns interactive user sign-ins, newest first, from within the retention period, and a sign-in typically appears within 6 hours. The examples read and export; they change nothing.

Option 1

Find failed sign-ins with PowerShell

Install the modules once, then connect and export the failed sign-ins of the last 7 days. The filter runs in Microsoft Graph, so only failures come back. Change $days to widen the window, up to the retention period.

PowerShell
# Install once, if the modules are not already installed.
Install-Module Microsoft.Graph.Authentication, Microsoft.Graph.Reports -Scope CurrentUser
PowerShell
$ErrorActionPreference = 'Stop'
$days = 7
$since = (Get-Date).ToUniversalTime().AddDays(-$days).ToString('s') + 'Z'
Connect-MgGraph -Scopes 'AuditLog.Read.All' -NoWelcome
try {
    $filter = "createdDateTime ge $since and status/errorCode ne 0"
    $failures = @(Get-MgAuditLogSignIn -All -Filter $filter)
    if ($failures.Count -eq 0) {
        Write-Output "No sign-in failed in the last $days days."
    } else {
        $failures | Select-Object CreatedDateTime, UserDisplayName, UserPrincipalName,
            AppDisplayName, ClientAppUsed, IPAddress,
            @{ Name = 'ErrorCode'; Expression = { $_.Status.ErrorCode } },
            @{ Name = 'FailureReason'; Expression = { $_.Status.FailureReason } },
            @{ Name = 'Country'; Expression = { $_.Location.CountryOrRegion } } |
            Export-Csv -Path './failed-sign-ins.csv' -NoTypeInformation -Encoding utf8
        $byUser = foreach ($person in ($failures | Group-Object UserPrincipalName)) {
            $latest = $person.Group | Sort-Object CreatedDateTime | Select-Object -Last 1
            $reasons = @($person.Group | Group-Object { $_.Status.FailureReason } |
                Sort-Object Count -Descending)
            [pscustomobject]@{
                UserPrincipalName = $person.Name
                Failures          = $person.Count
                LastFailure       = $latest.CreatedDateTime
                CommonReason      = $reasons[0].Name
            }
        }
        $byUser | Sort-Object Failures -Descending |
            Export-Csv -Path './failed-sign-ins-by-user.csv' -NoTypeInformation -Encoding utf8
        Write-Output "$($failures.Count) failed sign-ins for $(@($byUser).Count) sign-in names."
    }
} finally {
    Disconnect-MgGraph | Out-Null
}

The script writes every failure to 1 file and a second with 1 row per sign-in name, the most failures first, with its last failure and its most common reason. A sign-in name is what was typed, so a name that is no account in the tenant gets a row too. To look for 1 error, change ne 0 to eq and the code, such as eq 500121 for MFA prompts left unanswered.

Option 2

Review failed sign-ins in the admin centre

  1. Sign in to the Microsoft Entra admin centre as at least a Reports Reader.
  2. Go to Entra ID > Monitoring & health > Sign-in logs.
  3. Select Failure from the Status menu to show only failed sign-ins. Search by username or application to narrow the list.
  4. Select a failed sign-in to open its details and read the Sign-in error code and Failure reason, and the Conditional Access tab for the policies that applied.
  5. Close the details without changing anything.

This suits looking into 1 person's failed sign-in while they wait. The log lists 1 sign-in per row, so for who failed most across a week, use PowerShell or a report.

Common questions

Why does the script say the tenant doesn't have a premium licence?

Reading the sign-in logs with Microsoft Graph needs Microsoft Entra ID P1 or P2. Without it, read the logs in the admin centre instead, which shows them on every edition for 7 days. If the tenant has the licence and the error comes and goes, Microsoft says to add Directory.Read.All to the scopes.

Is every failure an attack?

No. Error 50058 means the person was authenticated but did not finish signing in, and 500121 means they did not complete the MFA prompt, often because they have not set MFA up. Enter any other code in Microsoft's error code lookup tool for its meaning and the fix it suggests.

How do I find accounts that never sign in at all?

A failed sign-in is still an attempt. For accounts with none, see how to find users who have never signed in.

Microsoft references

Technical references checked on 6 November 2026. The example scripts have been reviewed and syntax checked; they have not been run against a live tenant.

Talk to us about Altivane

Questions, or pricing? Get in touch.

Contact us