A set of technologies in .NET for building web applications and web services. Miscellaneous topics that do not fit into specific categories.
Hi,
Thanks for reaching out to this forum.
This occurs during the TDS login handshake before SQL authentication/authorization. If TrustServerCertificate=True or Encrypt=False is really in the effective connection string, the driver should either skip validation (TrustServerCertificate) or not negotiate encryption (Encrypt=False) unless the server forces it.
Since you have stated that you have tried this, I suggest the best course of action is troubleshooting this problem step by step.
Decision Tree:
- Log the actual connection string inside IIS.
- If it’s missing
TrustServerCertificate=True, fix configuration precedence. - If it includes it but still fails, test a standalone console app as the same identity.
- If console also fails: SQL Server encryption / certificate configuration issue.
- If console succeeds: web app identity / override issue.
- Once connectivity works, add proper certificate (optional Step 8) OR keep
TrustServerCertificate=True.
Step 1. Confirm the Real Error Context You already have the stack trace. We just accept: failure occurs during TLS handshake before migration runs.
Step 2. Log Effective Connection String at Runtime (Under IIS)
Add temporarily to Program.cs BEFORE AddDbContext:
var builder = WebApplication.CreateBuilder(args);
// TEMP: dump connection strings
var snapshot = builder.Configuration.AsEnumerable()
.Where(kv => kv.Key.StartsWith("ConnectionStrings"))
.ToList();
File.WriteAllLines(Path.Combine(AppContext.BaseDirectory, "conn-effective.txt"),
snapshot.Select(kv => $"{kv.Key} = {kv.Value}"));
Console.WriteLine("== ConnectionStrings ==");
foreach (var kv in snapshot) Console.WriteLine($"{kv.Key} = {kv.Value}");
After building the app (still in Program.cs):
var app = builder.Build();
// TEMP: log DbContext actual connection string
using (var scope = app.Services.CreateScope())
{
var ctx = scope.ServiceProvider.GetRequiredService<YourDbContext>();
var cs = ctx.Database.GetDbConnection().ConnectionString;
File.WriteAllText(Path.Combine(AppContext.BaseDirectory, "dbcontext-connection.txt"), cs);
}
Publish, browse once, then open the published folder/logs and inspect:
-
conn-effective.txt -
dbcontext-connection.txt
You MUST see:
TrustServerCertificate=True (or Encrypt=False if you are choosing that workaround — but prefer TrustServerCertificate=True if the server forces encryption).
If it is missing: proceed to Step 3.
Step 3. Check Configuration Overrides (Provider Precedence) Inspect for environment overrides:
- IIS Manager → Site → Configuration Editor →
system.webServer/aspNetCore→ look for<environmentVariables>. - Application Pool → Advanced Settings → Identity (note which user runs it).
- System/User Environment Variables: none should be named
ConnectionStrings__DefaultConnection. - Published
web.config: search forConnectionStrings__. - Confirm
appsettings.jsonand (if used)appsettings.Production.jsonin publish folder contain updated string:"ConnectionStrings": { "DefaultConnection": "Server=localhost\\SQLEXPRESS;Database=GateAccessPro;Trusted_Connection=True;TrustServerCertificate=True;MultipleActiveResultSets=True" }
Fix any override you find, republish, re-run Step 2.
Step 4. Test SQL Connectivity Under SAME Identity (Outside IIS Code) Open a command prompt running as the app pool identity (or temporarily change pool to a custom service account you can log on with):
sqlcmd -S localhost\SQLEXPRESS -E -Q "SELECT @@VERSION"
If this fails: SQL Server instance / permissions / network protocol issue (resolve before continuing).
If success, move to Step 5.
Step 5. Minimal Console App Connectivity Test Create a small console project (NET 7/8) on the server; run as same identity:
using Microsoft.Data.SqlClient;
var cs = "Server=localhost\\SQLEXPRESS;Database=GateAccessPro;Trusted_Connection=True;TrustServerCertificate=True;";
try
{
using var cn = new SqlConnection(cs);
cn.Open();
Console.WriteLine("OK: " + cn.ServerVersion);
}
catch (Exception ex)
{
Console.WriteLine("FAIL:\n" + ex);
}
Outcomes:
- Succeeds: The SQL stack is fine; web app config/identity mismatch.
- Fails with same SSL error: SQL Server encryption setting or cert trust problem (go to Step 7).
Step 6. Version + Package Sanity
Check .csproj for Microsoft.Data.SqlClient version (prefer current stable 5.x):
<ItemGroup>
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.0" />
</ItemGroup>
Rebuild & republish. Remove any lingering System.Data.SqlClient references to avoid mixed behaviors.
Step 7. Narrow Further (Force Encryption? Identity? Permissions?)
- Open SQL Server Configuration Manager → SQL Server Network Configuration → Protocols for SQLEXPRESS → TCP/IP → Properties → Flags → Force Encryption.
- If Force Encryption = Yes and you don’t have a trusted cert installed, you MUST use
TrustServerCertificate=True.
- If Force Encryption = Yes and you don’t have a trusted cert installed, you MUST use
- If after confirming the connection string includes
TrustServerCertificate=Trueit still fails:- You may actually be connecting to a different instance (e.g. a cached
LocalDB) → search published folder forlocaldb(findstr /S /I localdb *.*).
- You may actually be connecting to a different instance (e.g. a cached
- Once SSL error disappears, if you then get:
-
Login failed for user 'IIS APPPOOL\YourAppPool': create a login and user:CREATE LOGIN [IIS APPPOOL\YourAppPool] FROM WINDOWS; USE GateAccessPro; CREATE USER [IIS APPPOOL\YourAppPool] FOR LOGIN [IIS APPPOOL\YourAppPool]; ALTER ROLE db_owner ADD MEMBER [IIS APPPOOL\YourAppPool]; -- reduce later
-
- Temporarily remove automatic migrations to isolate connectivity:
try
{
using var scope = app.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<YourDbContext>();
if (await db.Database.CanConnectAsync())
Console.WriteLine("CanConnect OK");
else
Console.WriteLine("CanConnect FALSE");
}
catch (Exception e)
{
File.WriteAllText(Path.Combine(AppContext.BaseDirectory, "canconnect-error.txt"), e.ToString());
}
Step 8 (Optional but Proper): Install and Use a Trusted Certificate
Do this only after you’ve proven the diagnostic issue (wrong/overridden connection string) is solved, unless policy requires real TLS trust immediately.
- Obtain or create a certificate whose CN / SAN matches the machine name (e.g.
MYDEVBOXor FQDN). - Import into Local Computer > Personal (Certificates MMC).
- Grant private key read to SQL Server service account (
NT SERVICE\MSSQL$SQLEXPRESSor the custom account). - SQL Server Configuration Manager → Protocols for SQLEXPRESS → Properties → Certificate tab → select the cert.
- (Optional) Set Force Encryption = Yes.
- Restart SQL Server (SQLEXPRESS) service.
- Update connection string:
Server=MYDEVBOX;Database=GateAccessPro;Trusted_Connection=True;Encrypt=True;TrustServerCertificate=False;MultipleActiveResultSets=True; - If you used
localhostbefore, change to the machine name (certificate must match).
Final Reference Connection Strings
Development (bypassing trust while diagnosing):
Server=localhost\\SQLEXPRESS;Database=GateAccessPro;Trusted_Connection=True;TrustServerCertificate=True;MultipleActiveResultSets=True;
Production (with real cert):
Server=MYDEVBOX;Database=GateAccessPro;Trusted_Connection=True;Encrypt=True;TrustServerCertificate=False;MultipleActiveResultSets=True;
Please let me know if this helps. If the problem still persists, please give me results of the steps you've taken.