Sửa lỗi SSL 'The certificate chain was issued by an authority that is not trusted' trên SQL Server (Windows)

intermediate🪟 Windows2026-05-12| Windows 10/11, SQL Server 2016–2022, .NET / SSMS / pyodbc / JDBC clients

Error Message

A connection was successfully established with the server, but then an error occurred during the login process. (provider: SSL Provider, error: 0 - The certificate chain was issued by an authority that is not trusted.)
#sqlserver#ssl#certificate#windows#trusted-root

Chuyện gì đã xảy ra

Bạn đang kết nối đến SQL Server — có thể là một máy dev từ xa, một Docker container, hoặc một máy chủ production mới được cấp phát — và thay vì kết nối được, bạn nhận được thông báo sau:

A connection was successfully established with the server, but then an error occurred during the login process.
(provider: SSL Provider, error: 0 - The certificate chain was issued by an authority that is not trusted.)

TCP handshake đã thành công — server có thể truy cập được. Nhưng TLS bị lỗi vì chứng chỉ SSL của SQL Server được ký bởi một CA mà Windows không tin tưởng. Vấn đề này trở nên phổ biến hơn nhiều sau khi SQL Server 2022 và ODBC Driver 18 bắt đầu bật Encrypt=True theo mặc định. Nếu lỗi xuất hiện sau khi nâng cấp driver, đó chính xác là lý do.

Chẩn đoán trước

Đừng vội tìm cách khắc phục. Hãy xác định bạn đang gặp tình huống nào:

  • Chứng chỉ tự ký (self-signed cert) — SQL Server tự tạo chứng chỉ của mình khi cài đặt. Phổ biến trong môi trường dev và staging.
  • Chứng chỉ từ CA nội bộ — Được cấp bởi một CA của công ty chưa có trong kho Trusted Root của Windows.
  • Chứng chỉ hết hạn hoặc CN không khớp — Chứng chỉ tồn tại nhưng hostname không khớp hoặc đã hết hạn.

Kiểm tra chứng chỉ mà SQL Server đang thực sự sử dụng:

  • Mở SQL Server Configuration ManagerSQL Server Network ConfigurationProtocols for MSSQLSERVER → chuột phải chọn Properties → tab Certificate.
  • Ghi lại thumbprint. Sau đó xác minh chứng chỉ trong PowerShell:
# Liệt kê các cert trong kho LocalMachine\My (nơi SQL Server tra cứu)
Get-ChildItem Cert:\LocalMachine\My | Select-Object Subject, Thumbprint, NotAfter, Issuer

Đối chiếu thumbprint với những gì Configuration Manager hiển thị. Nếu Issuer hiển thị nội dung như CN=SQL Server Internal CA hoặc chỉ là tên máy, thì đó là chứng chỉ tự ký. Đó là nguyên nhân gây ra lỗi.

Giải pháp 1 — Tin tưởng chứng chỉ trên client (nhanh nhất cho môi trường dev)

Bạn kiểm soát các máy client và đây là server dev hoặc nội bộ? Hãy xuất chứng chỉ SQL Server và nhập vào kho Windows Trusted Root.

Bước 1: Xuất chứng chỉ từ server

# Chạy trên máy chủ SQL Server (PowerShell với quyền admin)
$thumb = "PASTE_THUMBPRINT_HERE"
$cert = Get-Item "Cert:\LocalMachine\My\$thumb"
Export-Certificate -Cert $cert -FilePath "C:\sqlserver.cer" -Type CERT

Bước 2: Sao chép file .cer sang máy client rồi nhập vào

# Chạy trên máy CLIENT (PowerShell với quyền admin)
Import-Certificate -FilePath "C:\sqlserver.cer" -CertStoreLocation "Cert:\LocalMachine\Root"

Thích dùng giao diện đồ họa? Double-click file .cerInstall CertificateLocal MachinePlace all certificates in the following storeTrusted Root Certification Authorities.

Xác minh

Get-ChildItem Cert:\LocalMachine\Root | Where-Object { $_.Subject -like "*SQLSERVERHOSTNAME*" }

Thử kết nối lại. Không cần thay đổi connection string — nó sẽ hoạt động ngay.

Giải pháp 2 — Thêm TrustServerCertificate=True vào connection string (bỏ qua nhanh)

Đối với dev local hoặc sửa tạm thời, bạn có thể yêu cầu driver bỏ qua toàn bộ việc xác thực chứng chỉ. Đừng đưa cái này lên production.

# .NET / ADO.NET
Server=myserver;Database=mydb;User Id=sa;Password=xxx;Encrypt=True;TrustServerCertificate=True;

# Python pyodbc
connection_string = (
    "DRIVER={ODBC Driver 18 for SQL Server};"
    "SERVER=myserver;"
    "DATABASE=mydb;"
    "UID=sa;PWD=xxx;"
    "Encrypt=yes;"
    "TrustServerCertificate=yes;"
)

# JDBC (Java)
jdbc:sqlserver://myserver:1433;databaseName=mydb;encrypt=true;trustServerCertificate=true;

Điều đáng biết: ODBC Driver 18 trở lên mặc định dùng Encrypt=yes. Driver 17 mặc định là Encrypt=no. Sự khác biệt một dòng này chính là lý do lỗi xuất hiện đột ngột sau khi nâng cấp driver mà không có thay đổi nào khác.

Giải pháp 3 — Cài chứng chỉ hợp lệ trên SQL Server (hướng đi cho production)

Môi trường production cần cách khắc phục thực sự. Dùng chứng chỉ từ CA công khai (Let's Encrypt hoàn toàn ổn, DigiCert nếu bạn cần EV) hoặc PKI nội bộ của tổ chức.

Cài chứng chỉ trên máy chủ SQL Server

# Nhập chứng chỉ PFX (có private key) vào LocalMachine\My
$pfxPath = "C:\certs\sqlserver.pfx"
$pfxPassword = ConvertTo-SecureString -String "yourpassword" -Force -AsPlainText
Import-PfxCertificate -FilePath $pfxPath -CertStoreLocation "Cert:\LocalMachine\My" -Password $pfxPassword

Gán chứng chỉ cho SQL Server

  • Mở SQL Server Configuration Manager.
  • Vào SQL Server Network ConfigurationProtocols for MSSQLSERVER → chuột phải → Properties → tab Certificate.
  • Chọn chứng chỉ mới từ danh sách thả xuống.
  • Khởi động lại dịch vụ SQL Server.
Restart-Service -Name MSSQLSERVER -Force

Bất kỳ client nào đã tin tưởng CA — máy tham gia domain với PKI doanh nghiệp, hoặc bất kỳ ai dùng CA công khai — đều kết nối sạch mà không cần thay đổi connection string.

Giải pháp 4 — Tắt mã hóa trên server (chỉ dành cho dev bị cô lập hoàn toàn)

Đang chạy SQL Server dev hoàn toàn bị cô lập mà mã hóa không mang lại lợi ích gì? Bạn có thể tắt hoàn toàn.

  • Trong SQL Server Configuration Manager → Protocols for MSSQLSERVER → Properties → tab Flags.
  • Đặt Force Encryption thành No.
  • Khởi động lại SQL Server.
  • Thêm Encrypt=False vào connection string (hoặc bỏ hoàn toàn nếu dùng ODBC Driver 17).

Chỉ dành cho môi trường dev bị cô lập. Tuyệt đối không áp dụng trên server chứa dữ liệu thực.

Xác nhận bản sửa đã hoạt động

# Kiểm tra nhanh với sqlcmd — không có flag TrustServerCertificate
sqlcmd -S myserver -U sa -P yourpassword -Q "SELECT @@VERSION"

# Hoặc kiểm tra với đoạn .NET tối giản
$conn = New-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = "Server=myserver;Database=master;User Id=sa;Password=xxx;Encrypt=True;"
$conn.Open()
Write-Host "Connected: $($conn.State)"
$conn.Close()

Thấy chuỗi phiên bản SQL Server hoặc Connected: Open? Bạn đã xong.

Những điều cần ghi nhớ

  • ODBC Driver 18 đã thay đổi giá trị mặc định. Driver 17 đi kèm với Encrypt=no; Driver 18 đổi thành Encrypt=yes. Kiểm tra phiên bản đang cài bằng Get-OdbcDriver -Name "*SQL*" — đây rất có thể là thủ phạm nếu lỗi xuất hiện mà không có thay đổi code nào.
  • TrustServerCertificate là mùi code xấu trong production. Ổn cho laptop cá nhân. Trước khi đưa lên production, hãy grep toàn bộ codebase và cấu hình CI — nó có thói quen lọt vào connection string của môi trường production.
  • Máy tham gia domain nhận cert CA tự động qua Group Policy. Nếu một số máy trong tổ chức kết nối được còn máy khác thì không, hãy kiểm tra xem máy bị lỗi có thực sự tham gia domain không. Máy bỏ lỡ đồng bộ GPO sẽ không có CA doanh nghiệp trong kho trust của nó.
  • SQL Server chạy trong container luôn dùng chứng chỉ tự ký. Mọi SQL Server instance chạy bằng Docker đều gặp lỗi này ngay từ đầu. Với container dev, thêm TrustServerCertificate=True vào connection string. Với container production, hãy mount chứng chỉ thực.

Related Error Notes