diff --git a/src/ZB.MOM.WW.MxGateway.Server/Diagnostics/AuthStoreHealthCheck.cs b/src/ZB.MOM.WW.MxGateway.Server/Diagnostics/AuthStoreHealthCheck.cs
new file mode 100644
index 0000000..59f1544
--- /dev/null
+++ b/src/ZB.MOM.WW.MxGateway.Server/Diagnostics/AuthStoreHealthCheck.cs
@@ -0,0 +1,40 @@
+using Microsoft.Data.Sqlite;
+using Microsoft.Extensions.Diagnostics.HealthChecks;
+using ZB.MOM.WW.MxGateway.Server.Security.Authentication;
+
+namespace ZB.MOM.WW.MxGateway.Server.Diagnostics;
+
+///
+/// Readiness probe: verifies the SQLite authentication store is reachable. The gateway
+/// authenticates every gRPC call against this store, so its reachability gates readiness.
+///
+public sealed class AuthStoreHealthCheck : IHealthCheck
+{
+ private readonly AuthSqliteConnectionFactory _connectionFactory;
+
+ public AuthStoreHealthCheck(AuthSqliteConnectionFactory connectionFactory) =>
+ _connectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory));
+
+ public async Task CheckHealthAsync(
+ HealthCheckContext context,
+ CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ await using SqliteConnection connection =
+ await _connectionFactory.OpenConnectionAsync(cancellationToken).ConfigureAwait(false);
+ await using SqliteCommand command = connection.CreateCommand();
+ command.CommandText = "SELECT 1;";
+ await command.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false);
+ return HealthCheckResult.Healthy("Auth store is reachable.");
+ }
+ catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
+ {
+ throw;
+ }
+ catch (Exception ex)
+ {
+ return HealthCheckResult.Unhealthy("Auth store is unreachable.", ex);
+ }
+ }
+}
diff --git a/src/ZB.MOM.WW.MxGateway.Tests/Diagnostics/AuthStoreHealthCheckTests.cs b/src/ZB.MOM.WW.MxGateway.Tests/Diagnostics/AuthStoreHealthCheckTests.cs
new file mode 100644
index 0000000..3a9aa1f
--- /dev/null
+++ b/src/ZB.MOM.WW.MxGateway.Tests/Diagnostics/AuthStoreHealthCheckTests.cs
@@ -0,0 +1,49 @@
+using Microsoft.Extensions.Diagnostics.HealthChecks;
+using Microsoft.Extensions.Options;
+using ZB.MOM.WW.MxGateway.Server.Configuration;
+using ZB.MOM.WW.MxGateway.Server.Diagnostics;
+using ZB.MOM.WW.MxGateway.Server.Security.Authentication;
+
+namespace ZB.MOM.WW.MxGateway.Tests.Diagnostics;
+
+public sealed class AuthStoreHealthCheckTests
+{
+ private static AuthSqliteConnectionFactory FactoryFor(string sqlitePath)
+ {
+ // GatewayOptions.Authentication and AuthenticationOptions.SqlitePath are both
+ // init-only, so populate them through object initializers.
+ var options = new GatewayOptions
+ {
+ Authentication = new AuthenticationOptions { SqlitePath = sqlitePath },
+ };
+ return new AuthSqliteConnectionFactory(Options.Create(options));
+ }
+
+ [Fact]
+ public async Task Healthy_WhenStoreReachable()
+ {
+ var path = Path.Combine(Path.GetTempPath(), $"authcheck-{Guid.NewGuid():N}.db");
+ try
+ {
+ var check = new AuthStoreHealthCheck(FactoryFor(path));
+ var result = await check.CheckHealthAsync(new HealthCheckContext());
+ Assert.Equal(HealthStatus.Healthy, result.Status);
+ }
+ finally { if (File.Exists(path)) File.Delete(path); }
+ }
+
+ [Fact]
+ public async Task Unhealthy_WhenPathUnusable()
+ {
+ // A regular file used as a parent directory forces the open to fail.
+ var bogus = Path.Combine(Path.GetTempPath(), $"authcheck-{Guid.NewGuid():N}");
+ await File.WriteAllTextAsync(bogus, "x");
+ try
+ {
+ var check = new AuthStoreHealthCheck(FactoryFor(Path.Combine(bogus, "store.db")));
+ var result = await check.CheckHealthAsync(new HealthCheckContext());
+ Assert.Equal(HealthStatus.Unhealthy, result.Status);
+ }
+ finally { if (File.Exists(bogus)) File.Delete(bogus); }
+ }
+}