You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
TLS Handshake failed: tls: failed to parse certificate from server: x509: negative serial number #755
Latest release to date shows the following error on certain certificates: TLS Handshake failed: tls: failed to parse certificate from server: x509: negative serial number
A new release using the latest Go version should be done to fix
Thanks for the report! Short version: this is almost certainly your SQL Server's self-signed certificate, not a sqlcmd bug, and a Go upgrade won't fix it.
What's happening
The error comes from Go's standard library (crypto/x509), not from sqlcmd or go-mssqldb directly. Since Go 1.23, the parser rejects X.509 certificates with negative serial numbers, because RFC 5280 §4.1.2.2 requires the serial to be a positive integer. In Go 1.23 there was an opt-out via GODEBUG=x509negativeserial=1; that knob was deprecated in 1.24 and removed in 1.25. sqlcmd is already built with Go 1.25, so rebuilding against a newer toolchain would make this stricter, not looser.
Why this is almost certainly SQL Server 2017
SQL Server's self-signed TLS certificate (the one it generates at startup when no admin-provided cert is configured) historically used a random 16-byte serial without clearing the high bit. About half the time the result DER-encodes as a negative integer. SQL Server 2017's generator was never fixed, and the certificate persists across restarts, so a server that drew an unlucky serial will fail every connection from any modern client.
We can confirm this is 2017-specific from the go-mssqldb CI itself (pr-validation.yml): the matrix runs 2017/2019/2022/2025, and only the 2017-latest branch sets GODEBUG=x509negativeserial=1 with the comment:
SQL 2017's self-signed certificate has a negative serial number that Go 1.23+ rejects by default. This GODEBUG override is only for CI testing against SQL Server 2017 and MUST NOT be used in production.
2019/2022/2025 don't need it.
Could you confirm SELECT @@VERSION and whether the cert is the auto-generated self-signed one (subject == issuer, matches the machine name) or one you provisioned? That tells us which fix applies.
Fixes, in order of correctness
Replace the SQL Server certificate with an RFC-compliant one. Any modern CA (current AD CS, OpenSSL with a positive -set_serial, public CAs) will do. This is the right long-term fix and also unblocks recent .NET, JDK 21+, and Python-on-current-OpenSSL clients that are tightening the same rule.
Disable encryption for this connection: sqlcmd -No ... (or -N false). This bypasses the TLS handshake entirely so the cert is never parsed. Only appropriate on a trusted network. Note: -C (trust server certificate) alone will not work, because parsing happens before validation, and the cert has to parse before we get a chance to skip verification.
Not recommended: building sqlcmd against Go 1.22 with GODEBUG=x509negativeserial=1. Maintenance dead end, and the GODEBUG no longer exists in Go 1.25.
What's coming on the driver side
go-mssqldb#356 is open to wrap this exact handshake error with actionable guidance (the GODEBUG context, the -No workaround, and a pointer to reissuing the cert), so the next sqlcmd release built against an updated driver will print something more useful than the bare x509: negative serial number. The underlying behavior won't change, but the diagnostic will.
We're going to close this as not actionable inside sqlcmd. Please reopen if your server cert is out of your control and -No isn't viable, so we can discuss it further.
Activity
dlevy-msft-sql commentedon May 19, 2026
Thanks for the report! Short version: this is almost certainly your SQL Server's self-signed certificate, not a sqlcmd bug, and a Go upgrade won't fix it.
What's happening
The error comes from Go's standard library (
crypto/x509), not from sqlcmd orgo-mssqldbdirectly. Since Go 1.23, the parser rejects X.509 certificates with negative serial numbers, because RFC 5280 §4.1.2.2 requires the serial to be a positive integer. In Go 1.23 there was an opt-out viaGODEBUG=x509negativeserial=1; that knob was deprecated in 1.24 and removed in 1.25. sqlcmd is already built with Go 1.25, so rebuilding against a newer toolchain would make this stricter, not looser.Why this is almost certainly SQL Server 2017
SQL Server's self-signed TLS certificate (the one it generates at startup when no admin-provided cert is configured) historically used a random 16-byte serial without clearing the high bit. About half the time the result DER-encodes as a negative integer. SQL Server 2017's generator was never fixed, and the certificate persists across restarts, so a server that drew an unlucky serial will fail every connection from any modern client.
We can confirm this is 2017-specific from the go-mssqldb CI itself (pr-validation.yml): the matrix runs 2017/2019/2022/2025, and only the
2017-latestbranch setsGODEBUG=x509negativeserial=1with the comment:2019/2022/2025 don't need it.
Could you confirm
SELECT @@VERSIONand whether the cert is the auto-generated self-signed one (subject == issuer, matches the machine name) or one you provisioned? That tells us which fix applies.Fixes, in order of correctness
-set_serial, public CAs) will do. This is the right long-term fix and also unblocks recent .NET, JDK 21+, and Python-on-current-OpenSSL clients that are tightening the same rule.sqlcmd -No ...(or-N false). This bypasses the TLS handshake entirely so the cert is never parsed. Only appropriate on a trusted network. Note:-C(trust server certificate) alone will not work, because parsing happens before validation, and the cert has to parse before we get a chance to skip verification.GODEBUG=x509negativeserial=1. Maintenance dead end, and the GODEBUG no longer exists in Go 1.25.What's coming on the driver side
go-mssqldb#356 is open to wrap this exact handshake error with actionable guidance (the GODEBUG context, the
-Noworkaround, and a pointer to reissuing the cert), so the next sqlcmd release built against an updated driver will print something more useful than the barex509: negative serial number. The underlying behavior won't change, but the diagnostic will.We're going to close this as not actionable inside sqlcmd. Please reopen if your server cert is out of your control and
-Noisn't viable, so we can discuss it further.jam-re commentedon May 21, 2026
It happens with mssql/server:2019-CU30-ubuntu-20.04 as well (sometimes) and
GODEBUG=x509negativeserial=1has to be setchore: remove mssql `x509negativeserial` workaround (#37853)
chore: remove mssql `x509negativeserial` workaround (go-gitea#37853)