{"record":{"id":"c989809495d53ff3","repo":"golang-migrate/migrate","slug":"to-use-tls-client-authentication-both-x-tls-cert","errorCode":null,"errorMessage":"to use TLS client authentication, both x-tls-cert and x-tls-key must not be empty","messagePattern":"to use TLS client authentication, both x-tls-cert and x-tls-key must not be empty","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"database/mysql/mysql.go","lineNumber":37,"sourceCode":"\n\t\"github.com/go-sql-driver/mysql\"\n\t\"github.com/golang-migrate/migrate/v4/database\"\n)\n\nvar _ database.Driver = (*Mysql)(nil) // explicit compile time type check\n\nfunc init() {\n\tdatabase.Register(\"mysql\", &Mysql{})\n}\n\nvar DefaultMigrationsTable = \"schema_migrations\"\n\nvar (\n\tErrDatabaseDirty    = fmt.Errorf(\"database is dirty\")\n\tErrNilConfig        = fmt.Errorf(\"no config\")\n\tErrNoDatabaseName   = fmt.Errorf(\"no database name\")\n\tErrAppendPEM        = fmt.Errorf(\"failed to append PEM\")\n\tErrTLSCertKeyConfig = fmt.Errorf(\"to use TLS client authentication, both x-tls-cert and x-tls-key must not be empty\")\n)\n\ntype Config struct {\n\tMigrationsTable  string\n\tDatabaseName     string\n\tNoLock           bool\n\tStatementTimeout time.Duration\n}\n\ntype Mysql struct {\n\t// mysql RELEASE_LOCK must be called from the same conn, so\n\t// just do everything over a single conn anyway.\n\tconn     *sql.Conn\n\tdb       *sql.DB\n\tisLocked atomic.Bool\n\n\tconfig *Config\n}","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/golang-migrate/migrate/blob/01a9643f1475e75bb6d6224ddeaf9d8e2434ca8a/database/mysql/mysql.go#L19-L55","documentation":"This library's MySQL driver supports TLS client (mutual) authentication via the custom DSN parameters x-tls-cert and x-tls-key. Because a client certificate and its private key only make sense as a pair, the driver rejects any configuration where exactly one of them is set and the other is empty. The error is returned during URL/DSN parsing in urlToMySQLConfig before any connection is made.","triggerScenarios":"Calling mysql.WithInstance/Open with a mysql:// URL that includes a custom tls=<name> param (non-bool, not skip-verify) plus an x-tls-ca, and setting exactly one of x-tls-cert or x-tls-key while the other is empty or missing (database/mysql/mysql.go:168-171).","commonSituations":"Developers paste a CA-based TLS URL and add only the certificate path, forgetting the key; environment-variable interpolation silently drops one of the two params; config templating leaves one field blank; splitting the pair across config files where one entry was renamed.","solutions":["Set both x-tls-cert and x-tls-key to the client certificate and private key file paths in the DSN","If client auth is not needed, remove both x-tls-cert and x-tls-key from the URL entirely (keep only x-tls-ca)","Verify the final composed DSN (log or print it, minus secrets) to confirm both params survived environment/templating expansion"],"exampleFix":"// before\ndsn := \"mysql://user:pass@tcp(db:3306)/app?tls=custom&x-tls-ca=/ca.pem&x-tls-cert=/client-cert.pem\"\n// after\ndsn := \"mysql://user:pass@tcp(db:3306)/app?tls=custom&x-tls-ca=/ca.pem&x-tls-cert=/client-cert.pem&x-tls-key=/client-key.pem\"","handlingStrategy":"validation","validationCode":"u, _ := url.Parse(dsn)\nq := u.Query()\nccert, ckey := q.Get(\"x-tls-cert\"), q.Get(\"x-tls-key\")\nif (ccert == \"\") != (ckey == \"\") {\n    return errors.New(\"x-tls-cert and x-tls-key must both be set or both omitted\")\n}","typeGuard":null,"tryCatchPattern":"drv, err := mysql.Open(dsn)\nif errors.Is(err, mysql.ErrTLSCertKeyConfig) {\n    return fmt.Errorf(\"TLS client auth misconfigured: set both x-tls-cert and x-tls-key: %w\", err)\n}","preventionTips":["Always configure the cert/key pair together from a single config struct so one cannot be set without the other","Validate the composed DSN in tests before deploying","If client auth is optional, omit both params rather than leaving one blank"],"tags":["mysql","tls","configuration","client-authentication"],"backgroundTag":"tls-client-cert-misconfigured","analyzedSha":"01a9643f1475e75bb6d6224ddeaf9d8e2434ca8a","analyzedAt":"2026-09-02T19:38:29.671Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}