{
    int         r;
 
+   SOCK_ERRNO_SET(0);
    ERR_clear_error();
    r = SSL_connect(conn->ssl);
    if (r <= 0)
    {
+       int         save_errno = SOCK_ERRNO;
        int         err = SSL_get_error(conn->ssl, r);
        unsigned long ecode;
 
            case SSL_ERROR_SYSCALL:
                {
                    char        sebuf[PG_STRERROR_R_BUFLEN];
-
-                   if (r == -1)
+                   unsigned long vcode;
+
+                   vcode = SSL_get_verify_result(conn->ssl);
+
+                   /*
+                    * If we get an X509 error here for failing to load the
+                    * local issuer cert, without an error in the socket layer
+                    * it means that verification failed due to a missing
+                    * system CA pool without it being a protocol error. We
+                    * inspect the sslrootcert setting to ensure that the user
+                    * was using the system CA pool. For other errors, log them
+                    * using the normal SYSCALL logging.
+                    */
+                   if (!save_errno && vcode == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY &&
+                       strcmp(conn->sslrootcert, "system") == 0)
+                       libpq_append_conn_error(conn, "SSL error: certificate verify failed: %s",
+                                               X509_verify_cert_error_string(vcode));
+                   else if (r == -1)
                        libpq_append_conn_error(conn, "SSL SYSCALL error: %s",
-                                         SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
+                                         SOCK_STRERROR(save_errno, sebuf, sizeof(sebuf)));
                    else
                        libpq_append_conn_error(conn, "SSL SYSCALL error: EOF detected");
                    pgtls_close(conn);
 
   "$default_ssl_connstr user=ssltestuser dbname=trustdb sslrootcert=system hostaddr=$SERVERHOSTADDR";
 
 # By default our custom-CA-signed certificate should not be trusted.
+# OpenSSL 3.0 reports a missing/invalid system CA as "unregistered schema"
+# instead of a failed certificate verification.
 $node->connect_fails(
    "$common_connstr sslmode=verify-full host=common-name.pg-ssltest.test",
    "sslrootcert=system does not connect with private CA",
-   expected_stderr => qr/SSL error: certificate verify failed/);
+   expected_stderr => qr/SSL error: (certificate verify failed|unregistered scheme)/);
 
 # Modes other than verify-full cannot be mixed with sslrootcert=system.
 $node->connect_fails(