diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
index 65c7809332e3c6a54bcef0c354df770a22d02a74..38f561886a1efa09bec8a7a1ef4b3b5b36250637 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -2159,9 +2159,8 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
   </para>
 
   <para>
-   If the private key is protected with a passphrase, the
-   server will prompt for the passphrase and will not start until it has
-   been entered.
+   The private key cannot be protected with a passphrase, as there is no
+   way to supply the passphrase to the server.
   </para>
 
   <para>
@@ -2315,8 +2314,8 @@ openssl req -new -text -out server.req
     you enter the local host name as <quote>Common Name</>; the challenge
     password can be left blank. The program will generate a key that is
     passphrase protected; it will not accept a passphrase that is less
-    than four characters long. To remove the passphrase (as you must if
-    you want automatic start-up of the server), run the commands:
+    than four characters long.  To remove the passphrase again (as you must),
+    next run the commands:
 <programlisting>
 openssl rsa -in privkey.pem -out server.key
 rm privkey.pem
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 4a39d7f74672c8d49c1b71e71e47c13cc131aebe..45ad41200384cc37c4ec9abe541bc094b0650f19 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -75,6 +75,7 @@ static DH  *load_dh_file(int keylength);
 static DH  *load_dh_buffer(const char *, size_t);
 static DH  *generate_dh_parameters(int prime_len, int generator);
 static DH  *tmp_dh_cb(SSL *s, int is_export, int keylength);
+static int	ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata);
 static int	verify_cb(int, X509_STORE_CTX *);
 static void info_cb(const SSL *ssl, int type, int args);
 static bool initialize_ecdh(SSL_CTX *context, bool failOnError);
@@ -203,6 +204,11 @@ be_tls_init(bool failOnError)
 	 */
 	SSL_CTX_set_mode(context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
 
+	/*
+	 * Override OpenSSL's default handling of passphrase-protected files.
+	 */
+	SSL_CTX_set_default_passwd_cb(context, ssl_passwd_cb);
+
 	/*
 	 * Load and verify server's certificate and private key
 	 */
@@ -1060,6 +1066,29 @@ tmp_dh_cb(SSL *s, int is_export, int keylength)
 	return r;
 }
 
+/*
+ *	Passphrase collection callback
+ *
+ * If OpenSSL is told to use a passphrase-protected server key, by default
+ * it will issue a prompt on /dev/tty and try to read a key from there.
+ * That's completely no good for a postmaster SIGHUP cycle, not to mention
+ * SSL context reload in an EXEC_BACKEND postmaster child.  So override it
+ * with this dummy function that just returns an empty passphrase,
+ * guaranteeing failure.  Later we might think about collecting a passphrase
+ * at server start and feeding it to OpenSSL repeatedly, but we'd still
+ * need this callback for that.
+ */
+static int
+ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata)
+{
+	ereport(LOG,
+			(errcode(ERRCODE_CONFIG_FILE_ERROR),
+			 errmsg("server's private key file requires a passphrase")));
+	Assert(size > 0);
+	buf[0] = '\0';
+	return 0;
+}
+
 /*
  *	Certificate verification callback
  *