diff --git a/agent/ShopDbEndpointAgent.Core/CertificateExpiryMonitor.cs b/agent/ShopDbEndpointAgent.Core/CertificateExpiryMonitor.cs
new file mode 100644
index 00000000..0bfca037
--- /dev/null
+++ b/agent/ShopDbEndpointAgent.Core/CertificateExpiryMonitor.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace ShopDbEndpointAgent.Core;
+
+///
+/// Background service that periodically checks client certificate expiry.
+/// If certificate expires within 30 days, triggers renewal and service restart.
+///
+/// This is critical for long-running agents that don't restart frequently.
+/// Without this, an agent running > 30 days will have an expired cert with no
+/// automatic renewal, causing authentication failures.
+///
+public class CertificateExpiryMonitor : BackgroundService
+{
+ private readonly ILogger logger;
+ private readonly ILogger renewalLogger;
+ private readonly AgentConfig config;
+ private readonly IHostApplicationLifetime lifetime;
+
+ private const int CHECK_INTERVAL_HOURS = 24;
+ private const int RENEWAL_THRESHOLD_DAYS = 30;
+
+ public CertificateExpiryMonitor(
+ ILogger logger,
+ ILogger renewalLogger,
+ AgentConfig config,
+ IHostApplicationLifetime lifetime)
+ {
+ this.logger = logger;
+ this.renewalLogger = renewalLogger;
+ this.config = config;
+ this.lifetime = lifetime;
+ }
+
+ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+ {
+ // Wait 1 hour after service start before first check (let agent stabilize)
+ await Task.Delay(TimeSpan.FromHours(1), stoppingToken);
+
+ while (!stoppingToken.IsCancellationRequested)
+ {
+ try
+ {
+ await CheckCertificateExpiry();
+ }
+ catch (Exception ex)
+ {
+ logger.LogError(ex, "Certificate expiry check failed");
+ }
+
+ // Check every 24 hours
+ await Task.Delay(TimeSpan.FromHours(CHECK_INTERVAL_HOURS), stoppingToken);
+ }
+ }
+
+ private async Task CheckCertificateExpiry()
+ {
+ if (string.IsNullOrWhiteSpace(config.ClientCertThumbprint))
+ {
+ // No client cert configured, nothing to check
+ return;
+ }
+
+ logger.LogDebug("Performing periodic certificate expiry check");
+
+ // Use same renewal logic as startup check
+ var renewal = new CertificateRenewal(renewalLogger, config);
+ bool didRenew = await renewal.CheckAndRenewIfNeeded();
+
+ if (didRenew)
+ {
+ logger.LogWarning(
+ "Certificate was renewed during periodic check. Agent has been running " +
+ "for an extended period without restart. Stopping service to apply new " +
+ "certificate. Service manager will restart the agent.");
+
+ // Stop the application gracefully
+ // Windows Service Manager will restart it (if configured as Automatic)
+ lifetime.StopApplication();
+ }
+ }
+}
diff --git a/agent/ShopDbEndpointAgent/Program.cs b/agent/ShopDbEndpointAgent/Program.cs
index 8e0ca23a..00409093 100644
--- a/agent/ShopDbEndpointAgent/Program.cs
+++ b/agent/ShopDbEndpointAgent/Program.cs
@@ -214,6 +214,12 @@ static async Task RunHostAsync(AgentConfig config, string agentVersion,
builder.Services.AddHostedService(sp => sp.GetRequiredService());
builder.Services.AddHostedService(sp => sp.GetRequiredService());
+ // Background monitor for certificate expiry (critical for long-running agents)
+ // Checks every 24 hours, triggers renewal if < 30 days remaining
+ // Without this, agents running > 30 days would have expired certs
+ builder.Services.AddSingleton();
+ builder.Services.AddHostedService(sp => sp.GetRequiredService());
+
await builder.Build().RunAsync();
}