*** a/src/backend/libpq/auth.c
--- b/src/backend/libpq/auth.c
***************
*** 273,278 **** ClientAuthentication(Port *port)
--- 273,304 ----
  				 errmsg("missing or erroneous pg_hba.conf file"),
  				 errhint("See server log for details.")));
  
+ 	/*
+ 	 * This is the first point where we have access to the hba record for
+ 	 * the current connection, so perform any verifications based on the
+ 	 * hba options field that should be done *before* the authentication
+ 	 * here.
+ 	 */
+ 	if (port->hba->clientcert)
+ 	{
+ 		/*
+ 		 * When we parse pg_hba.conf, we have already made sure that we have
+ 		 * been able to load a certificate store. Thus, if a certificate is
+ 		 * present on the client, it has been verified against our root
+ 		 * certificate store, and the connection would have been aborted
+ 		 * already if it didn't verify ok.
+ 		 */
+ 		if (!port->peer)
+ 		{
+ 			ereport(FATAL,
+ 					(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
+ 					 errmsg("connection requires a valid client certificate")));
+ 		}
+ 	}
+ 
+ 	/*
+ 	 * Now proceed to do the actual authentication check
+ 	 */
  	switch (port->hba->auth_method)
  	{
  		case uaReject:
*** a/src/backend/libpq/be-secure.c
--- b/src/backend/libpq/be-secure.c
***************
*** 128,133 **** static const char *SSLerrmessage(void);
--- 128,134 ----
  #define RENEGOTIATION_LIMIT (512 * 1024 * 1024)
  
  static SSL_CTX *SSL_context = NULL;
+ static bool ssl_loaded_verify_locations = false;
  
  /* GUC variable controlling SSL cipher list */
  char	   *SSLCipherSuites = NULL;
***************
*** 229,234 **** secure_destroy(void)
--- 230,248 ----
  }
  
  /*
+  * Indicate if we have loaded the root CA store to verify certificates
+  */
+ bool
+ secure_loaded_verify_locations(void)
+ {
+ #ifdef USE_SSL
+ 	return ssl_loaded_verify_locations;
+ #endif
+ 
+ 	return false;
+ }
+ 
+ /*
   *	Attempt to negotiate secure session.
   */
  int
***************
*** 780,794 **** initialize_SSL(void)
  		elog(FATAL, "could not set the cipher list (no valid ciphers available)");
  
  	/*
! 	 * Require and check client certificates only if we have a root.crt file.
  	 */
! 	if (!SSL_CTX_load_verify_locations(SSL_context, ROOT_CERT_FILE, NULL))
  	{
! 		/* Not fatal - we do not require client certificates */
  		ereport(LOG,
  				(errmsg("could not load root certificate file \"%s\": %s",
  						ROOT_CERT_FILE, SSLerrmessage()),
! 				 errdetail("Will not verify client certificates.")));
  	}
  	else
  	{
--- 794,821 ----
  		elog(FATAL, "could not set the cipher list (no valid ciphers available)");
  
  	/*
! 	 * Attempt to load CA store, so we can verify client certificates if needed.
  	 */
! 	if (access(ROOT_CERT_FILE, R_OK))
  	{
! 		/*
! 		 * Root certificate file simply not found. Don't log an error here, because
! 		 * it's quite likely the user isn't planning on using client certificates.
! 		 */
! 		ssl_loaded_verify_locations = false;
! 	}
! 	else if (!SSL_CTX_load_verify_locations(SSL_context, ROOT_CERT_FILE, NULL))
! 	{
! 		/*
! 		 * File was there, but we could not load it. This means the file is somehow
! 		 * broken, and we should log this. Don't log it as a fatal error, because
! 		 * there is still a chance that the user isn't going to use client certs.
! 		 */
! 		ssl_loaded_verify_locations = false;
  		ereport(LOG,
  				(errmsg("could not load root certificate file \"%s\": %s",
  						ROOT_CERT_FILE, SSLerrmessage()),
! 				 errdetail("Will not be able to verify client certificates.")));
  	}
  	else
  	{
***************
*** 821,833 **** initialize_SSL(void)
  								ROOT_CRL_FILE, SSLerrmessage()),
  						 errdetail("Certificates will not be checked against revocation list.")));
  			}
- 		}
  
! 		SSL_CTX_set_verify(SSL_context,
! 						   (SSL_VERIFY_PEER |
! 							SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
! 							SSL_VERIFY_CLIENT_ONCE),
! 						   verify_cb);
  	}
  }
  
--- 848,865 ----
  								ROOT_CRL_FILE, SSLerrmessage()),
  						 errdetail("Certificates will not be checked against revocation list.")));
  			}
  
! 			/*
! 			 * Always ask for SSL client cert, but don't fail if it's not presented. We'll fail later in this case,
! 			 * based on what we find in pg_hba.conf.
! 			 */
! 			SSL_CTX_set_verify(SSL_context,
! 							   (SSL_VERIFY_PEER |
! 								SSL_VERIFY_CLIENT_ONCE),
! 							   verify_cb);
! 
! 			ssl_loaded_verify_locations = true;
! 		}
  	}
  }
  
*** a/src/backend/libpq/hba.c
--- b/src/backend/libpq/hba.c
***************
*** 873,878 **** parse_hba_line(List *line, int line_num, HbaLine *parsedline)
--- 873,910 ----
  					INVALID_AUTH_OPTION("map", "ident, krb5, gssapi and sspi");
  				parsedline->usermap = pstrdup(c);
  			}
+ 			else if (strcmp(token, "clientcert") == 0)
+ 			{
+ 				/*
+ 				 * Since we require ctHostSSL, this really can never happen on non-SSL-enabled
+ 				 * builds, so don't bother checking for USE_SSL.
+ 				 */
+ 				if (parsedline->conntype != ctHostSSL)
+ 				{
+ 					ereport(LOG,
+ 							(errcode(ERRCODE_CONFIG_FILE_ERROR),
+ 							 errmsg("clientcert can only be configured for \"hostssl\" rows"),
+ 							 errcontext("line %d of configuration file \"%s\"",
+ 										line_num, HbaFileName)));
+ 					goto hba_other_error;
+ 				}
+ 				if (strcmp(c, "1") == 0)
+ 				{
+ 					if (!secure_loaded_verify_locations())
+ 					{
+ 						ereport(LOG,
+ 								(errcode(ERRCODE_CONFIG_FILE_ERROR),
+ 								 errmsg("client certificates can only be checked if a root certificate store is available"),
+ 								 errdetail("make sure the root certificate store is present and readable"),
+ 								 errcontext("line %d of configuration file \"%s\"",
+ 											line_num, HbaFileName)));
+ 						goto hba_other_error;
+ 					}
+ 					parsedline->clientcert = true;
+ 				}
+ 				else
+ 					parsedline->clientcert = false;
+ 			}
  			else if (strcmp(token, "pamservice") == 0)
  			{
  				REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
*** a/src/include/libpq/hba.h
--- b/src/include/libpq/hba.h
***************
*** 55,60 **** typedef struct
--- 55,61 ----
  	int			ldapport;
  	char	   *ldapprefix;
  	char	   *ldapsuffix;
+ 	bool		clientcert;
  } HbaLine;
  
  typedef struct Port hbaPort;
*** a/src/include/libpq/libpq.h
--- b/src/include/libpq/libpq.h
***************
*** 67,72 **** extern void pq_endcopyout(bool errorAbort);
--- 67,73 ----
   * prototypes for functions in be-secure.c
   */
  extern int	secure_initialize(void);
+ extern bool secure_loaded_verify_locations(void);
  extern void secure_destroy(void);
  extern int	secure_open_server(Port *port);
  extern void secure_close(Port *port);
