diff --git a/src/test/Makefile b/src/test/Makefile
index 0fd7eab..e6a7154 100644
--- a/src/test/Makefile
+++ b/src/test/Makefile
@@ -12,6 +12,6 @@ subdir = src/test
 top_builddir = ../..
 include $(top_builddir)/src/Makefile.global
 
-SUBDIRS = regress isolation
+SUBDIRS = regress isolation ssl
 
 $(recurse)
diff --git a/src/test/ssl/Makefile b/src/test/ssl/Makefile
new file mode 100644
index 0000000..8e0db47
--- /dev/null
+++ b/src/test/ssl/Makefile
@@ -0,0 +1,59 @@
+#-------------------------------------------------------------------------
+#
+# Makefile for src/test/ssl
+#
+# Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+# Portions Copyright (c) 1994, Regents of the University of California
+#
+# src/test/ssl/Makefile
+#
+#-------------------------------------------------------------------------
+
+subdir = src/test/ssl
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+CERTIFICATES := serverroot server-cn-and-alt-names \
+	server-cn-only server-single-alt-name server-multiple-alt-names \
+	server-no-names \
+	clientroot client
+
+SSLFILES := $(CERTIFICATES:%=ssl/%.key) $(CERTIFICATES:%=ssl/%.crt)
+
+sslfiles: $(SSLFILES)
+
+# Rule for creating private/public key pairs
+ssl/%.key:
+	openssl genrsa -out $@ 1024
+	chmod 0600 $@
+
+# Rule for creating CA certificates (client and server)
+ssl/%root.crt: ssl/%root.key %root.config
+	openssl req -new -key ssl/$*root.key -days 36500 -out ssl/$*root.crt -x509 -config $*root.config
+	echo "00" > ssl/$*root.srl
+
+# Server certificates, signed by server root CA:
+ssl/server-%.crt: ssl/server-%.key ssl/serverroot.crt
+# Generate a Certificate Sign Request (CSR)
+	openssl req -new -key ssl/server-$*.key -out ssl/server-$*.csr -config server-$*.config
+# Sign the certificate with the right CA
+	openssl x509 -req -in ssl/server-$*.csr -CA ssl/serverroot.crt -CAkey ssl/serverroot.key -CAserial ssl/serverroot.srl -out ssl/server-$*.crt -extfile server-$*.config -extensions v3_req
+	rm ssl/server-$*.csr
+
+# Client certificate, signed by the client root CA:
+ssl/client.crt: ssl/client.key ssl/clientroot.crt
+# Generate a Certificate Sign Request (CSR)
+	openssl req -new -key ssl/client.key -out ssl/client.csr -config client.config
+# Sign the certificate with the right CA
+	openssl x509 -req -in ssl/client.csr -CA ssl/clientroot.crt -CAkey ssl/clientroot.key -CAserial ssl/clientroot.srl -out ssl/client.crt
+	rm ssl/client.csr
+
+sslfiles-clean:
+	rm -f $(SSLFILES) ssl/client-root.srl ssl/server-root.srl
+
+check:
+	$(prove_check)
+
+installcheck:
+	rm -rf tmp_check
+	$(prove_installcheck)
diff --git a/src/test/ssl/README b/src/test/ssl/README
new file mode 100644
index 0000000..dfd2d79
--- /dev/null
+++ b/src/test/ssl/README
@@ -0,0 +1,43 @@
+src/test/ssl/README
+
+SSL regression tests
+====================
+
+This directory contains a test suite for SSL support.
+
+Running the tests
+=================
+
+    make check
+
+Certificates
+============
+
+The test suite needs a set of public/private key pairs and certificates to
+run:
+
+serverroot.crt: CA used to sign server certificates
+clientroot.crt: CA used to sign client certificates
+server-*.crt: server certificate, with small variations in the hostnames
+              present in the certificate.
+client.crt: a client certificate, for user "ssltestuser"
+
+For convenience, these keypairs and certificates are included in the ssl/
+subdirectory, but the Makefile also contains a rule, "make sslfiles", to
+recreate them if you want to make changes.
+
+
+TODO
+====
+
+* Allow the client-side of the tests to be run on different host easily.
+  Currently, you have to manually set up the certificates for the right
+  hostname, and modify the test file to skip setting up the server. And you
+  have to modify the server to accept connections from the client host.
+
+* Add more test coverage:
+  - CRLs
+  - intermediary CAs
+  - server.crt file with multiple certificates, and the private key in
+    server.key chooses the certificate to present to clients. (and the same
+    in client-side)
diff --git a/src/test/ssl/ServerSetup.pm b/src/test/ssl/ServerSetup.pm
new file mode 100644
index 0000000..0d6adc5
--- /dev/null
+++ b/src/test/ssl/ServerSetup.pm
@@ -0,0 +1,93 @@
+# This module sets up a test server, for the SSL regression tests.
+#
+# The server is configured as follows:
+#
+# - SSL enabled, with ssl/server.crt and ssl/server.key as the server cert.
+# - ssl/clientroot.crt as the CA root for validating client certs.
+# - reject non-SSL connections
+# - a database called trustdb that lets anyone in
+# - another database called certdb that uses certificate authentiction, ie.
+#   the client must present a valid certificate signed by the client CA
+# - two users, called ssltestuser and anotheruser.
+#
+# The server is configured to only accept connections from localhost. If you
+# want to run the client from another host, you'll have to configure that
+# manually. You'll also need to create a new server certificate, because the
+# one included is issued for "localhost", so the client won't accept it in
+# verify-full mode.
+#
+package ServerSetup;
+
+use strict;
+use warnings;
+use TestLib;
+
+use Exporter 'import';
+our @EXPORT = qw(
+  configure_test_server_for_ssl switch_server_cert
+);
+
+sub configure_test_server_for_ssl
+{
+  my $tempdir = $_[0];
+
+  # Create test users and databases
+  psql 'postgres', "CREATE USER ssltestuser";
+  psql 'postgres', "CREATE USER anotheruser";
+  psql 'postgres', "CREATE DATABASE trustdb";
+  psql 'postgres', "CREATE DATABASE certdb";
+
+  # enable logging etc.
+  open CONF, ">>$tempdir/pgdata/postgresql.conf";
+  print CONF "fsync=off\n";
+  print CONF "log_connections=on\n";
+  print CONF "log_hostname=on\n";
+  print CONF "log_statement=all\n";
+
+  # enable SSL and set up server key
+  print CONF "include 'sslconfig.conf'";
+
+  close CONF;
+
+
+  # Copy all server certificates and keys, and client root cert, to the data dir
+  system_or_bail "cp ssl/server-*.crt '$tempdir'/pgdata";
+  system_or_bail "cp ssl/server-*.key '$tempdir'/pgdata";
+  system_or_bail "chmod 0600 '$tempdir'/pgdata/server-*.key";
+  system_or_bail "cp ssl/clientroot.crt '$tempdir'/pgdata";
+
+  # Only accept SSL connections from localhost. Our tests don't depend on this
+  # but seems best to keep it as narrow as possible for security reasons.
+  #
+  # When connecting to certdb, also check the client certificate.
+  open HBA, ">$tempdir/pgdata/pg_hba.conf";
+  print HBA "# TYPE  DATABASE        USER            ADDRESS                 METHOD\n";
+  print HBA "hostssl trustdb         ssltestuser     127.0.0.1/32            trust\n";
+  print HBA "hostssl trustdb         ssltestuser     ::1/128                 trust\n";
+  print HBA "hostssl certdb          ssltestuser     127.0.0.1/32            cert\n";
+  print HBA "hostssl certdb          ssltestuser     ::1/128                 cert\n";
+  close HBA;
+}
+
+# Change the configuration to use given server cert file, and restart
+# the server so that the configuration takes effect.
+sub switch_server_cert
+{
+  my $tempdir = $_[0];
+  my $certfile = $_[1];
+
+  open SSLCONF, ">$tempdir/pgdata/sslconfig.conf";
+  print SSLCONF "ssl=on\n";
+  print SSLCONF "ssl_ca_file='clientroot.crt'\n";
+  print SSLCONF "ssl_cert_file='$certfile.crt'\n";
+  print SSLCONF "ssl_key_file='$certfile.key'\n";
+  close SSLCONF;
+
+  # Stop and restart server to reload the new config. We cannot use
+  # restart_test_server() because that overrides listen_addresses to only all
+  # Unix domain socket connections.
+
+  system_or_bail 'pg_ctl', 'stop', '-D', "$tempdir/pgdata", '-w';
+  system_or_bail 'pg_ctl', 'start', '-D', "$tempdir/pgdata", '-w', '-l',
+        "$tempdir/logfile";
+}
diff --git a/src/test/ssl/client.config b/src/test/ssl/client.config
new file mode 100644
index 0000000..2e9d40d
--- /dev/null
+++ b/src/test/ssl/client.config
@@ -0,0 +1,13 @@
+# An OpenSSL format CSR config file for creating a client certificate.
+#
+# The certificate is for user "ssltestuser".
+
+[ req ]
+distinguished_name     = req_distinguished_name
+prompt                 = no
+
+[ req_distinguished_name ]
+CN                     = ssltestuser
+
+# no extensions in client certs
+[ v3_req ]
diff --git a/src/test/ssl/clientroot.config b/src/test/ssl/clientroot.config
new file mode 100644
index 0000000..8b28bcf
--- /dev/null
+++ b/src/test/ssl/clientroot.config
@@ -0,0 +1,10 @@
+# An OpenSSL format CSR config file for creating the client root certificate.
+#
+# This certificate is used to sign client certificates. It is self-signed.
+
+[ req ]
+distinguished_name     = req_distinguished_name
+prompt                 = no
+
+[ req_distinguished_name ]
+CN                     = Test CA for PostgreSQL SSL regression test client certs
diff --git a/src/test/ssl/server-cn-and-alt-names.config b/src/test/ssl/server-cn-and-alt-names.config
new file mode 100644
index 0000000..f82cceb
--- /dev/null
+++ b/src/test/ssl/server-cn-and-alt-names.config
@@ -0,0 +1,23 @@
+# An OpenSSL format CSR config file for creating a server certificate.
+#
+
+[ req ]
+distinguished_name     = req_distinguished_name
+req_extensions         = v3_req
+prompt                 = no
+
+[ req_distinguished_name ]
+# Note: According to RFC 2818 and 6125, the CN is ignored, when SANs are
+# present. In practice, the hostname that's put in the CN field is always
+# also listed as a SAN, but we intentionally don't do that here so that we
+# can test adherence to those RFCs.
+CN = common-name.pg-ssltest.test
+OU = PostgreSQL test suite
+
+# For Subject Alternative Names
+[ v3_req ]
+subjectAltName = @alt_names
+
+[ alt_names ]
+DNS.1 = dns1.alt-name.pg-ssltest.test
+DNS.2 = dns2.alt-name.pg-ssltest.test
diff --git a/src/test/ssl/serverroot.config b/src/test/ssl/serverroot.config
new file mode 100644
index 0000000..fcac4b9
--- /dev/null
+++ b/src/test/ssl/serverroot.config
@@ -0,0 +1,10 @@
+# An OpenSSL format CSR config file for creating the server root certificate.
+#
+# This certificate is used to sign server certificates. It is self-signed.
+
+[ req ]
+distinguished_name     = req_distinguished_name
+prompt                 = no
+
+[ req_distinguished_name ]
+CN                     = Test CA for PostgreSQL SSL regression test server certs
diff --git a/src/test/ssl/ssl/client.crt b/src/test/ssl/ssl/client.crt
new file mode 100644
index 0000000..cb4d640
--- /dev/null
+++ b/src/test/ssl/ssl/client.crt
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIBxzCCATACAQEwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UEAww3VGVzdCBDQSBm
+b3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IGNsaWVudCBjZXJ0czAe
+Fw0xNDA5MTIxMzU3MjJaFw0xNDEwMTIxMzU3MjJaMBYxFDASBgNVBAMMC3NzbHRl
+c3R1c2VyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZAGGRpHWYdjSOMSTr
+J3r+4NNlZ95oK0K+/dLjGo/4HaiWp3bdkzQQcyzr5Y+N6n8czuM9GH0gQcI5mh0E
+8Unt/VJja8NT/lZ4fcanThP5WkfRAqOQUgcu0jP5pX5zjVfH+AV6a11UhCQykVkE
+jN5wfAAsksHPwot4eXO10yEmjwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAKpj5yUC
+GVHLjO1lF0Qqz4Ks/GeO4HyV9uioiWa+OETRsSU6G06nte0wrKpHKK/LlAjP2hq7
++kkLlipQ7JEChpstXjuXKC1esjbcXKGXZvs8YLHnJHYA0bAC0Xi0dq3RmxK+zJ9B
+f1w9JXpXrzuVC5hmO4KZmpQfdVaWu5+SC5ay
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client.key b/src/test/ssl/ssl/client.key
new file mode 100644
index 0000000..7fb85fc
--- /dev/null
+++ b/src/test/ssl/ssl/client.key
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXgIBAAKBgQDZAGGRpHWYdjSOMSTrJ3r+4NNlZ95oK0K+/dLjGo/4HaiWp3bd
+kzQQcyzr5Y+N6n8czuM9GH0gQcI5mh0E8Unt/VJja8NT/lZ4fcanThP5WkfRAqOQ
+Ugcu0jP5pX5zjVfH+AV6a11UhCQykVkEjN5wfAAsksHPwot4eXO10yEmjwIDAQAB
+AoGBAISqwfvrwuVSJzFjhEGsInse8r8FcKjZAfaIcdzciXZUk5R/j6FJdMQ11hnm
+gAxweAQhzDW2+hC1g0v6F5HE/r+72QKxA2x1qRVdWnr5k3AOS9ZG92omXmsPxf3Z
+lesnmhEzMqCP+4c8o/dhY5hTd7FcvXmYevO3/iKnYtG2spPxAkEA98EynTfYzPgS
+7KlUKPLr/vv2xvmLTEZrv+vlwO2zEOFleZJcKh7+08F6VCw4+91Y0LKJtRjtyoXR
+m/a/5d4QOQJBAOA5LLRpcUHHhQtMT0Drf9rDczg8LI+SqRQaJ2IFUeWacnwS72rb
+PeAA9ppGCoayvdh7p/pC1oNfpBUfhDt6XQcCQQDnykaSNGePDCCYbashTHRicFTm
+vx0F1XSFcCvZnglDp7yKStYTSkBa2M6b5WvCp8mqJv8TASmnqh767ZWHd4RxAkEA
+k7EVYUCS+WESoX6CNaDpdo+HNWNtdqSD+lm/1zDp4PL6tf9C9H+1IfeAd93q0Q6r
+Pg01eALOiXpV+hPoZcUTwQJAECmxAJvZB1B9J9RTlVQpMfUBSNk1zv6RsR5kqLG7
+vuCWneLUwZLF7dqtF6wKL6kJkEGY4cgaADKKZVTnJ40mLw==
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
new file mode 100644
index 0000000..a7eaa35
--- /dev/null
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -0,0 +1,186 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 29;
+use ServerSetup;
+
+# Like TestLib.pm, we use IPC::Run
+BEGIN
+{
+	eval {
+		require IPC::Run;
+		import IPC::Run qw(run start);
+		1;
+	} or do
+	{
+		plan skip_all => "IPC::Run not available";
+	  }
+}
+
+#### Some configuration
+
+# This is the hostname used to connect to the server. This cannot be a
+# hostname, because the server certificate is always for the domain
+# postgresql-ssl-regression.test.
+my $SERVERHOSTADDR='127.0.0.1';
+
+my $tempdir = TestLib::tempdir;
+
+
+# Define a couple of helper functions to test connecting to the server.
+
+my $common_connstr;
+
+sub run_test_psql {
+	my $connstr = $_[0];
+	my $logstring = $_[1];
+
+	my $cmd = [ 'psql',
+				'-A', '-t',
+				'-c', "SELECT 'connected with $connstr'",
+				'-d', "$connstr"
+		];
+
+    open CLIENTLOG, ">>$tempdir/client-log" or die "Could not open client-log file";
+	print CLIENTLOG "\n# Running test: $connstr $logstring\n";
+	close CLIENTLOG;
+
+	my $result = run $cmd, '>>', "$tempdir/client-log", '2>&1';
+	return $result;
+}
+
+#
+# The first argument is a (part of a) connection string, and it's also printed
+# out as the test case name. It is appended to $common_connstr global variable,
+# which also contains a libpq connection string.
+#
+# The second argument is a hostname to connect to.
+sub test_connect_ok {
+	my $connstr = $_[0];
+
+	my $result = run_test_psql("$common_connstr $connstr", "(should succeed)");
+	ok($result, $connstr);
+}
+
+sub test_connect_fails {
+	my $connstr = $_[0];
+
+	my $result = run_test_psql("$common_connstr $connstr", "(should fail)");
+	ok(!$result, "$connstr (should fail)");
+}
+
+# The client's private key must not be world-readable. Git doesn't track
+# permissions (except for the executable bit), so they might be wrong after
+# a checkout.
+system_or_bail "chmod 0600 ssl/client.key";
+
+#### Part 0. Set up the server.
+
+diag "setting up data directory in \"$tempdir\"...";
+start_test_server($tempdir);
+configure_test_server_for_ssl($tempdir);
+switch_server_cert($tempdir, 'server-cn-only');
+
+### Part 1. Run client-side tests.
+###
+### Test that libpq accepts/rejects the connection correctly, depending
+### on sslmode and whether the server's certificate looks correct. No
+### client certificate is used in these tests.
+
+diag "running client tests...";
+
+$common_connstr="user=ssltestuser dbname=trustdb sslcert=invalid hostaddr=$SERVERHOSTADDR host=common-name.pg-ssltest.test";
+
+# The server should not accept non-SSL connections
+diag "test that the server doesn't accept non-SSL connections";
+test_connect_fails("sslmode=disable");
+
+# Try without a root cert. In sslmode=require, this should work. In verify-ca
+# or verify-full mode it should fail
+diag "connect without server root cert";
+test_connect_ok   ("sslrootcert=invalid sslmode=require");
+test_connect_fails("sslrootcert=invalid sslmode=verify-ca");
+test_connect_fails("sslrootcert=invalid sslmode=verify-full");
+
+# Try with wrong root cert, should fail. (we're using the client CA as the
+# root, but the server's key is signed by the server CA)
+diag "connect without wrong server root cert";
+test_connect_fails("sslrootcert=ssl/clientroot.crt sslmode=require");
+test_connect_fails("sslrootcert=ssl/clientroot.crt sslmode=verify-ca");
+test_connect_fails("sslrootcert=ssl/clientroot.crt sslmode=verify-full");
+
+# And finally, with the correct root cert.
+diag "connect with correct server root cert";
+test_connect_ok   ("sslrootcert=ssl/serverroot.crt sslmode=require");
+test_connect_ok   ("sslrootcert=ssl/serverroot.crt sslmode=verify-ca");
+test_connect_ok   ("sslrootcert=ssl/serverroot.crt sslmode=verify-full");
+
+# Check that connecting with verify-full fails, when the hostname doesn't
+# match the hostname in the server's certificate.
+diag "test mismatch between hostname and server certificate";
+$common_connstr="user=ssltestuser dbname=trustdb sslcert=invalid sslrootcert=ssl/serverroot.crt hostaddr=$SERVERHOSTADDR sslmode=verify-full";
+
+test_connect_ok   ("sslmode=require host=wronghost.test");
+test_connect_ok   ("sslmode=verify-ca host=wronghost.test");
+test_connect_fails("sslmode=verify-full host=wronghost.test");
+
+# Test Subject Alternative Names.
+switch_server_cert($tempdir, 'server-multiple-alt-names');
+
+diag "test hostname matching with X509 Subject Alternative Names";
+$common_connstr="user=ssltestuser dbname=trustdb sslcert=invalid sslrootcert=ssl/serverroot.crt hostaddr=$SERVERHOSTADDR sslmode=verify-full";
+
+test_connect_ok   ("host=dns1.alt-name.pg-ssltest.test");
+test_connect_ok   ("host=dns2.alt-name.pg-ssltest.test");
+test_connect_ok   ("host=foo.wildcard.pg-ssltest.test");
+
+test_connect_fails("host=wronghost.alt-name.pg-ssltest.test");
+test_connect_fails("host=deep.subdomain.wildcard.pg-ssltest.test");
+
+# Test certificate with a single Subject Alternative Name. (this gives a
+# slightly different error message, that's all)
+switch_server_cert($tempdir, 'server-single-alt-name');
+
+diag "test hostname matching with a single X509 Subject Alternative Name";
+$common_connstr="user=ssltestuser dbname=trustdb sslcert=invalid sslrootcert=ssl/serverroot.crt hostaddr=$SERVERHOSTADDR sslmode=verify-full";
+
+test_connect_ok   ("host=dns1.alt-name.pg-ssltest.test");
+
+test_connect_fails("host=wronghost.alt-name.pg-ssltest.test");
+test_connect_fails("host=deep.subdomain.wildcard.pg-ssltest.test");
+
+# Test server certificate with a CN and SANs. Per RFCs 2818 and 6125, the CN
+# should be ignored when the certificate has both.
+switch_server_cert($tempdir, 'server-cn-and-alt-names');
+
+diag "test certificate with both a CN and SANs";
+$common_connstr="user=ssltestuser dbname=trustdb sslcert=invalid sslrootcert=ssl/serverroot.crt hostaddr=$SERVERHOSTADDR sslmode=verify-full";
+
+test_connect_ok   ("host=dns1.alt-name.pg-ssltest.test");
+test_connect_ok   ("host=dns2.alt-name.pg-ssltest.test");
+test_connect_fails("host=common-name.pg-ssltest.test");
+
+# Finally, test a server certificate that has no CN or SANs. Of course, that's
+# not a very sensible certificate, but libpq should handle it gracefully.
+switch_server_cert($tempdir, 'server-no-names');
+$common_connstr="user=ssltestuser dbname=trustdb sslcert=invalid sslrootcert=ssl/serverroot.crt hostaddr=$SERVERHOSTADDR";
+
+test_connect_ok("sslmode=verify-ca host=common-name.pg-ssltest.test");
+test_connect_fails("sslmode=verify-full host=common-name.pg-ssltest.test");
+
+
+### Part 2. Server-side tests.
+###
+### Test certificate authorization.
+
+diag "Testing certificate authorization...";
+$common_connstr="sslrootcert=ssl/serverroot.crt sslmode=require dbname=certdb hostaddr=$SERVERHOSTADDR";
+
+# no client cert
+test_connect_fails("user=ssltestuser sslcert=invalid");
+
+# correct client cert
+test_connect_ok   ("user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client.key");
+
+# client cert belonging to another user
+test_connect_fails("user=anotheruser sslcert=ssl/client.crt sslkey=ssl/client.key");
