alibaba/canal · critical · CertificateException

Server certificate identity check failed. The certificate Co

Error message

Server certificate identity check failed. The certificate Common Name '{}' does not match with '{}'.

What it means

Thrown during VERIFY_IDENTITY hostname verification when none of the certificates' CN values in the chain equals the hostName the client connected to (socket.getInetAddress().getHostName()). The message lists the CNs found and the expected host. This is the classic TLS hostname-mismatch failure for MySQL SSL.

Source

Thrown at driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/BioSocketChannelPool.java:307

                        String dn = certificate.getSubjectX500Principal().getName(X500Principal.RFC2253);
                        String cn = null;
                        try {
                            LdapName ldapDN = new LdapName(dn);
                            for (Rdn rdn : ldapDN.getRdns()) {
                                if (rdn.getType().equalsIgnoreCase("CN")) {
                                    cn = rdn.getValue().toString();
                                    break;
                                }
                            }
                        } catch (InvalidNameException e) {
                            throw new CertificateException(
                                "Failed to retrieve the Common Name (CN) from the server certificate.");
                        }
                        expectHostNames.add(cn);
                    }

                    if (!expectHostNames.contains(this.hostName)) {
                        throw new CertificateException(
                            "Server certificate identity check failed. The certificate Common Name "
                                                       + expectHostNames.stream()
                                                           .map(h -> "'" + h + "'")
                                                           .collect(Collectors.joining(", "))
                                                       + " does not match with '" + this.hostName + "'.");
                    }

                }
            }
        }

        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            this.origTm.checkClientTrusted(chain, authType);
        }
    }

}

View on GitHub (pinned to 87be50e876)

Solutions

  1. Connect using the exact hostname that appears in the certificate CN.
  2. Reissue the server certificate so its CN matches the address clients use (and include SANs).
  3. Ensure canals.master.address / jdbc URL host matches the cert CN.
  4. If hostname match is not enforceable, downgrade to SslMode.VERIFY_CA (chain trusted, no hostname check).
  5. Add the hostname to Subject Alternative Names if the cert supports SAN.

Example fix

# before
# canal.instance.master.address = 10.0.0.5:3306
# cert CN = mysql.internal.example.com -> mismatch

# after (option A: connect by the cert name)
canal.instance.master.address = mysql.internal.example.com:3306
# option B: reissue cert with SAN covering the IP
# [alt_names]
# IP.1 = 10.0.0.5
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the configured host matches a CN in the cert before enabling VERIFY_IDENTITY
String host = addressHost; // what the client connects to
Set<String> cns = extractCNs(serverCert);
if (!cns.contains(host)) { /* reissue cert or connect by the cert CN, or use VERIFY_CA */ }

Type guard

public static boolean hostMatchesCert(String host, X509Certificate cert) {
    try {
        String dn = cert.getSubjectX500Principal().getName(X500Principal.RFC2253);
        for (javax.naming.ldap.Rdn rdn : new javax.naming.ldap.LdapName(dn).getRdns()) {
            if (rdn.getType().equalsIgnoreCase("CN") && host.equals(rdn.getValue().toString())) return true;
        }
    } catch (Exception ignore) {}
    return false;
}

Try / catch

try {
    sslSocket.startHandshake();
} catch (javax.net.ssl.SSLHandshakeException e) {
    Throwable c = e.getCause();
    if (c instanceof java.security.cert.CertificateException
        && c.getMessage().contains("identity check failed")) {
        // fix canal.instance.master.address or reissue cert; or use VERIFY_CA
    }
    throw e;
}

Prevention

When it happens

Trigger: Connecting to a MySQL host whose certificate CN does not match the hostname/IP the client used (e.g. connecting by IP while the cert CN is a DNS name, or to a replica whose cert was minted for the primary's name). Triggered only in VERIFY_IDENTITY mode.

Common situations: Connecting by IP address but cert CN is a domain; cert issued for a different cluster node; wildcard/SAN not honored (parser only checks CN); misconfigured canal.instance.master.address that does not match the cert; copied a cert across failover replicas without reissuing.

Understand the failure class

Related errors


AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14). Data as JSON: /api/errors/fab9f60a8d5f6365. Report an issue: GitHub.