else
       LDAP_LIBS_FE="-lldap $EXTRA_LDAP_LIBS"
     fi
+    for ac_func in ldap_initialize
+do :
+  ac_fn_c_check_func "$LINENO" "ldap_initialize" "ac_cv_func_ldap_initialize"
+if test "x$ac_cv_func_ldap_initialize" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LDAP_INITIALIZE 1
+_ACEOF
+
+fi
+done
+
   else
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldap_bind in -lwldap32" >&5
 $as_echo_n "checking for ldap_bind in -lwldap32... " >&6; }
 
     else
       LDAP_LIBS_FE="-lldap $EXTRA_LDAP_LIBS"
     fi
+    AC_CHECK_FUNCS([ldap_initialize])
   else
     AC_CHECK_LIB(wldap32, ldap_bind, [], [AC_MSG_ERROR([library 'wldap32' is required for LDAP])])
     LDAP_LIBS_FE="-lwldap32"
 
        </para>
       </listitem>
      </varlistentry>
+     <varlistentry>
+      <term><literal>ldapscheme</literal></term>
+      <listitem>
+       <para>
+        Set to <literal>ldaps</literal> to use LDAPS.  This is a non-standard
+        way of using LDAP over SSL, supported by some LDAP server
+        implementations.  See also the <literal>ldaptls</literal> option for
+        an alternative.
+       </para>
+      </listitem>
+     </varlistentry>
      <varlistentry>
       <term><literal>ldaptls</literal></term>
       <listitem>
        <para>
-        Set to 1 to make the connection between PostgreSQL and the
-        LDAP server use TLS encryption. Note that this only encrypts
-        the traffic to the LDAP server — the connection to the client
-        will still be unencrypted unless SSL is used.
+        Set to 1 to make the connection between PostgreSQL and the LDAP server
+        use TLS encryption.  This uses the <literal>StartTLS</literal>
+        operation per RFC 4513.  See also the <literal>ldapscheme</literal>
+        option for an alternative.
        </para>
       </listitem>
      </varlistentry>
     </variablelist>
+   </para>
+
+   <para>
+    Note that using <literal>ldapscheme</literal> or
+    <literal>ldaptls</literal> only encrypts the traffic between the
+    PostgreSQL server and the LDAP server.  The connection between the
+    PostgreSQL server and the PostgreSQL client will still be unencrypted
+    unless SSL is used there as well.
+   </para>
 
+   <para>
     The following options are used in simple bind mode only:
     <variablelist>
      <varlistentry>
       </listitem>
      </varlistentry>
     </variablelist>
+   </para>
 
+   <para>
     The following options are used in search+bind mode only:
     <variablelist>
      <varlistentry>
          An RFC 4516 LDAP URL.  This is an alternative way to write some of the
          other LDAP options in a more compact and standard form.  The format is
 <synopsis>
-ldap://<replaceable>host</replaceable>[:<replaceable>port</replaceable>]/<replaceable>basedn</replaceable>[?[<replaceable>attribute</replaceable>][?[<replaceable>scope</replaceable>][?[<replaceable>filter</replaceable>]]]]
+ldap[s]://<replaceable>host</replaceable>[:<replaceable>port</replaceable>]/<replaceable>basedn</replaceable>[?[<replaceable>attribute</replaceable>][?[<replaceable>scope</replaceable>][?[<replaceable>filter</replaceable>]]]]
 </synopsis>
          <replaceable>scope</replaceable> must be one
          of <literal>base</literal>, <literal>one</literal>, <literal>sub</literal>,
         </para>
 
         <para>
-         For non-anonymous binds, <literal>ldapbinddn</literal>
-         and <literal>ldapbindpasswd</literal> must be specified as separate
-         options.
+         The URL scheme <literal>ldaps</literal> chooses the LDAPS method for
+         making LDAP connections over SSL, equivalent to using
+         <literal>ldapscheme=ldaps</literal>.  To use encrypted LDAP
+         connections using the <literal>StartTLS</literal> operation, use the
+         normal URL scheme <literal>ldap</literal> and specify the
+         <literal>ldaptls</literal> option in addition to
+         <literal>ldapurl</literal>.
         </para>
 
         <para>
-         To use encrypted LDAP connections, the <literal>ldaptls</literal>
-         option has to be used in addition to <literal>ldapurl</literal>.
-         The <literal>ldaps</literal> URL scheme (direct SSL connection) is not
-         supported.
+         For non-anonymous binds, <literal>ldapbinddn</literal>
+         and <literal>ldapbindpasswd</literal> must be specified as separate
+         options.
         </para>
 
         <para>
 
 static int
 InitializeLDAPConnection(Port *port, LDAP **ldap)
 {
+       const char *scheme;
        int                     ldapversion = LDAP_VERSION3;
        int                     r;
 
-       *ldap = ldap_init(port->hba->ldapserver, port->hba->ldapport);
+       scheme = port->hba->ldapscheme;
+       if (scheme == NULL)
+               scheme = "ldap";
+#ifdef WIN32
+       *ldap = ldap_sslinit(port->hba->ldapserver,
+                                                port->hba->ldapport,
+                                                strcmp(scheme, "ldaps") == 0);
        if (!*ldap)
        {
-#ifndef WIN32
-               ereport(LOG,
-                               (errmsg("could not initialize LDAP: %m")));
-#else
                ereport(LOG,
                                (errmsg("could not initialize LDAP: error code %d",
                                                (int) LdapGetLastError())));
-#endif
+
+               return STATUS_ERROR;
+       }
+#else
+#ifdef HAVE_LDAP_INITIALIZE
+       {
+               char       *uri;
+
+               uri = psprintf("%s://%s:%d", scheme, port->hba->ldapserver,
+                                          port->hba->ldapport);
+               r = ldap_initialize(ldap, uri);
+               pfree(uri);
+               if (r != LDAP_SUCCESS)
+               {
+                       ereport(LOG,
+                                       (errmsg("could not initialize LDAP: %s",
+                                                       ldap_err2string(r))));
+
+                       return STATUS_ERROR;
+               }
+       }
+#else
+       if (strcmp(scheme, "ldaps") == 0)
+       {
+               ereport(LOG,
+                               (errmsg("ldaps not supported with this LDAP library")));
+
+               return STATUS_ERROR;
+       }
+       *ldap = ldap_init(port->hba->ldapserver, port->hba->ldapport);
+       if (!*ldap)
+       {
+               ereport(LOG,
+                               (errmsg("could not initialize LDAP: %m")));
+
                return STATUS_ERROR;
        }
+#endif
+#endif
 
        if ((r = ldap_set_option(*ldap, LDAP_OPT_PROTOCOL_VERSION, &ldapversion)) != LDAP_SUCCESS)
        {
        }
 
        if (port->hba->ldapport == 0)
-               port->hba->ldapport = LDAP_PORT;
+       {
+               if (port->hba->ldapscheme != NULL &&
+                       strcmp(port->hba->ldapscheme, "ldaps") == 0)
+                       port->hba->ldapport = LDAPS_PORT;
+               else
+                       port->hba->ldapport = LDAP_PORT;
+       }
 
        sendAuthRequest(port, AUTH_REQ_PASSWORD, NULL, 0);
 
 
                        return false;
                }
 
-               if (strcmp(urldata->lud_scheme, "ldap") != 0)
+               if (strcmp(urldata->lud_scheme, "ldap") != 0 &&
+                       strcmp(urldata->lud_scheme, "ldaps") != 0)
                {
                        ereport(elevel,
                                        (errcode(ERRCODE_CONFIG_FILE_ERROR),
                        return false;
                }
 
+               if (urldata->lud_scheme)
+                       hbaline->ldapscheme = pstrdup(urldata->lud_scheme);
                if (urldata->lud_host)
                        hbaline->ldapserver = pstrdup(urldata->lud_host);
                hbaline->ldapport = urldata->lud_port;
                else
                        hbaline->ldaptls = false;
        }
+       else if (strcmp(name, "ldapscheme") == 0)
+       {
+               REQUIRE_AUTH_OPTION(uaLDAP, "ldapscheme", "ldap");
+               if (strcmp(val, "ldap") != 0 && strcmp(val, "ldaps") != 0)
+                       ereport(elevel,
+                                       (errcode(ERRCODE_CONFIG_FILE_ERROR),
+                                        errmsg("invalid ldapscheme value: \"%s\"", val),
+                                        errcontext("line %d of configuration file \"%s\"",
+                                                               line_num, HbaFileName)));
+               hbaline->ldapscheme = pstrdup(val);
+       }
        else if (strcmp(name, "ldapserver") == 0)
        {
                REQUIRE_AUTH_OPTION(uaLDAP, "ldapserver", "ldap");
 
        char       *pamservice;
        bool            pam_use_hostname;
        bool            ldaptls;
+       char       *ldapscheme;
        char       *ldapserver;
        int                     ldapport;
        char       *ldapbinddn;
 
 /* Define to 1 if you have the <ldap.h> header file. */
 #undef HAVE_LDAP_H
 
+/* Define to 1 if you have the `ldap_initialize' function. */
+#undef HAVE_LDAP_INITIALIZE
+
 /* Define to 1 if you have the `crypto' library (-lcrypto). */
 #undef HAVE_LIBCRYPTO
 
 
 use warnings;
 use TestLib;
 use PostgresNode;
-use Test::More tests => 15;
+use Test::More tests => 19;
 
 my ($slapd, $ldap_bin_dir, $ldap_schema_dir);
 
 $ENV{PATH} = "$ldap_bin_dir:$ENV{PATH}" if $ldap_bin_dir;
 
 my $ldap_datadir = "${TestLib::tmp_check}/openldap-data";
+my $slapd_certs = "${TestLib::tmp_check}/slapd-certs";
 my $slapd_conf = "${TestLib::tmp_check}/slapd.conf";
 my $slapd_pidfile = "${TestLib::tmp_check}/slapd.pid";
 my $slapd_logfile = "${TestLib::tmp_check}/slapd.log";
 my $ldap_conf = "${TestLib::tmp_check}/ldap.conf";
 my $ldap_server = 'localhost';
 my $ldap_port = int(rand() * 16384) + 49152;
+my $ldaps_port = $ldap_port + 1;
 my $ldap_url = "ldap://$ldap_server:$ldap_port";
+my $ldaps_url = "ldaps://$ldap_server:$ldaps_port";
 my $ldap_basedn = 'dc=example,dc=net';
 my $ldap_rootdn = 'cn=Manager,dc=example,dc=net';
 my $ldap_rootpw = 'secret';
 database ldif
 directory $ldap_datadir
 
+TLSCACertificateFile $slapd_certs/ca.crt
+TLSCertificateFile $slapd_certs/server.crt
+TLSCertificateKeyFile $slapd_certs/server.key
+
 suffix "dc=example,dc=net"
 rootdn "$ldap_rootdn"
 rootpw $ldap_rootpw});
 
+# don't bother to check the server's cert (though perhaps we should)
+append_to_file($ldap_conf,
+qq{TLS_REQCERT never
+});
+
 mkdir $ldap_datadir or die;
+mkdir $slapd_certs or die;
+
+system_or_bail "openssl", "req", "-new", "-nodes", "-keyout", "$slapd_certs/ca.key", "-x509", "-out", "$slapd_certs/ca.crt", "-subj", "/cn=CA";
+system_or_bail "openssl", "req", "-new", "-nodes", "-keyout", "$slapd_certs/server.key", "-out", "$slapd_certs/server.csr", "-subj", "/cn=server";
+system_or_bail "openssl", "x509", "-req", "-in", "$slapd_certs/server.csr", "-CA", "$slapd_certs/ca.crt", "-CAkey", "$slapd_certs/ca.key", "-CAcreateserial", "-out", "$slapd_certs/server.crt";
 
-system_or_bail $slapd, '-f', $slapd_conf, '-h', $ldap_url;
+system_or_bail $slapd, '-f', $slapd_conf, '-h', "$ldap_url $ldaps_url";
 
 END
 {
 
 $ENV{'LDAPURI'} = $ldap_url;
 $ENV{'LDAPBINDDN'} = $ldap_rootdn;
+$ENV{'LDAPCONF'} = $ldap_conf;
 
 note "loading LDAP data";
 
 
 note "diagnostic message";
 
+# note bad ldapprefix with a question mark that triggers a diagnostic message
+unlink($node->data_dir . '/pg_hba.conf');
+$node->append_conf('pg_hba.conf', qq{local all all ldap ldapserver=$ldap_server ldapport=$ldap_port ldapprefix="?uid=" ldapsuffix=""});
+$node->reload;
+
+$ENV{"PGPASSWORD"} = 'secret1';
+test_access($node, 'test1', 2, 'any attempt fails due to bad search pattern');
+
+note "TLS";
+
+# request StartTLS with ldaptls=1
+unlink($node->data_dir . '/pg_hba.conf');
+$node->append_conf('pg_hba.conf', qq{local all all ldap ldapserver=$ldap_server ldapport=$ldap_port ldapbasedn="$ldap_basedn" ldapsearchfilter="(uid=\$username)" ldaptls=1});
+$node->reload;
+
+$ENV{"PGPASSWORD"} = 'secret1';
+test_access($node, 'test1', 0, 'StartTLS');
+
+# request LDAPS with ldapscheme=ldaps
+unlink($node->data_dir . '/pg_hba.conf');
+$node->append_conf('pg_hba.conf', qq{local all all ldap ldapserver=$ldap_server ldapscheme=ldaps ldapport=$ldaps_port ldapbasedn="$ldap_basedn" ldapsearchfilter="(uid=\$username)"});
+$node->reload;
+
+$ENV{"PGPASSWORD"} = 'secret1';
+test_access($node, 'test1', 0, 'LDAPS');
+
+# request LDAPS with ldapurl=ldaps://...
+unlink($node->data_dir . '/pg_hba.conf');
+$node->append_conf('pg_hba.conf', qq{local all all ldap ldapurl="$ldaps_url/$ldap_basedn??sub?(uid=\$username)"});
+$node->reload;
+
+$ENV{"PGPASSWORD"} = 'secret1';
+test_access($node, 'test1', 0, 'LDAPS with URL');
+
+# bad combination of LDAPS and StartTLS
 unlink($node->data_dir . '/pg_hba.conf');
-$node->append_conf('pg_hba.conf', qq{local all all ldap ldapserver=$ldap_server ldapport=$ldap_port ldapprefix="uid=" ldapsuffix=",dc=example,dc=net" ldaptls=1});
+$node->append_conf('pg_hba.conf', qq{local all all ldap ldapurl="$ldaps_url/$ldap_basedn??sub?(uid=\$username)" ldaptls=1});
 $node->reload;
 
 $ENV{"PGPASSWORD"} = 'secret1';
-test_access($node, 'test1', 2, 'any attempt fails due to unsupported TLS');
+test_access($node, 'test1', 2, 'bad combination of LDAPS and StartTLS');