diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index cad51caca9c7ff634fb240cc85e93a17eaa0a7d9..e6180c762eec9e5f8fd082cf93087d846195e5b7 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/client-auth.sgml,v 1.52 2003/06/25 01:20:50 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/client-auth.sgml,v 1.53 2003/07/26 13:50:01 momjian Exp $
 -->
 
 <chapter id="client-authentication">
@@ -83,13 +83,15 @@ $Header: /cvsroot/pgsql/doc/src/sgml/client-auth.sgml,v 1.52 2003/06/25 01:20:50
   </para>
 
   <para>
-   A record may have one of the five formats
+   A record may have one of the seven formats
 <synopsis>
 local   <replaceable>database</replaceable>  <replaceable>user</replaceable>  <replaceable>authentication-method</replaceable>  <optional><replaceable>authentication-option</replaceable></optional>
 host    <replaceable>database</replaceable>  <replaceable>user</replaceable>  <replaceable>IP-address</replaceable>  <replaceable>IP-mask</replaceable>  <replaceable>authentication-method</replaceable>  <optional><replaceable>authentication-option</replaceable></optional>
 hostssl  <replaceable>database</replaceable>  <replaceable>user</replaceable>  <replaceable>IP-address</replaceable>  <replaceable>IP-mask</replaceable>  <replaceable>authentication-method</replaceable>  <optional><replaceable>authentication-option</replaceable></optional>
+hostnossl  <replaceable>database</replaceable>  <replaceable>user</replaceable>  <replaceable>IP-address</replaceable>  <replaceable>IP-mask</replaceable>  <replaceable>authentication-method</replaceable>  <optional><replaceable>authentication-option</replaceable></optional>
 host    <replaceable>database</replaceable>  <replaceable>user</replaceable>  <replaceable>IP-address</replaceable>/<replaceable>CIDR-mask</replaceable>  <replaceable>authentication-method</replaceable>  <optional><replaceable>authentication-option</replaceable></optional>
 hostssl  <replaceable>database</replaceable>  <replaceable>user</replaceable>  <replaceable>IP-address</replaceable>/<replaceable>CIDR-mask</replaceable>  <replaceable>authentication-method</replaceable>  <optional><replaceable>authentication-option</replaceable></optional>
+hostnossl  <replaceable>database</replaceable>  <replaceable>user</replaceable>  <replaceable>IP-address</replaceable>/<replaceable>CIDR-mask</replaceable>  <replaceable>authentication-method</replaceable>  <optional><replaceable>authentication-option</replaceable></optional>
 </synopsis>
    The meaning of the fields is as follows:
 
@@ -136,6 +138,17 @@ hostssl  <replaceable>database</replaceable>  <replaceable>user</replaceable>  <
      </listitem>
     </varlistentry>
 
+    <varlistentry>
+     <term><literal>hostnossl</literal></term>
+     <listitem>
+      <para>
+       This record is similar to <literal>hostssl</> but with the
+	   opposite logic: it matches only regular connection attempts not
+	   using SSL.
+      </para>
+     </listitem>
+    </varlistentry>
+
     <varlistentry>
      <term><replaceable>database</replaceable></term>
      <listitem>
@@ -196,8 +209,8 @@ hostssl  <replaceable>database</replaceable>  <replaceable>user</replaceable>  <
       </para>
 
       <para>
-       These fields only apply to <literal>host</literal> and
-       <literal>hostssl</literal> records.
+       These fields only apply to <literal>host</literal>,
+       <literal>hostssl</literal>, and <literal>hostnossl</> records.
       </para>
      </listitem>
     </varlistentry>
@@ -224,8 +237,8 @@ hostssl  <replaceable>database</replaceable>  <replaceable>user</replaceable>  <
       </para>
 
       <para>
-       This field only applies to <literal>host</literal> and
-       <literal>hostssl</literal> records.
+       This field only applies to <literal>host</literal>,
+       <literal>hostssl</literal>, and <literal>hostnossl</> records.
       </para>
      </listitem>
     </varlistentry>  
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index fa2db652b267156c16b43077c8ca6043200588be..1ebbd314439b7e6998bca3217d75e91a4e6c1985 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.128 2003/07/23 17:27:28 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.129 2003/07/26 13:50:01 momjian Exp $
 -->
 
  <chapter id="libpq">
@@ -206,14 +206,44 @@ PGconn *PQconnectdb(const char *conninfo);
      </listitem>
     </varlistentry>
 
+    <varlistentry>
+     <term><literal>sslmode</literal></term>
+     <listitem>
+	 <para>
+      This option determines whether or with what priority an <acronym>SSL</>
+      connection will be negotiated with the server. There are four
+      modes: <literal>disable</> will attempt only an unencrypted
+      <acronym>SSL</> connection; <literal>allow</> will negotiate,
+      trying first a non-<acronym>SSL</> connection, then if that fails,
+      trying an <acronym>SSL</> connection; <literal>prefer</>
+	  (the default) will negotiate, trying first an <acronym>SSL</> connection,
+	  then if that fails, trying a regular non-<acronym>SSL</> connection;
+      <literal>require</> will try only an <acronym>SSL</> connection.
+	 </para>
+	 <para>
+	  If <productname>PostgreSQL</> is compiled without SSL support,
+	  using option <literal>require</> will cause an error, and options
+	  <literal>allow</> and <literal>prefer</> will be tolerated but
+	  <application>libpq</> will be unable to negotiate an <acronym>SSL</>
+	  connection.
+     </para>
+     </listitem>
+    </varlistentry>
+
     <varlistentry>
      <term><literal>requiressl</literal></term>
      <listitem>
      <para>
-      If set to 1, an <acronym>SSL</acronym> connection to the server is required.
+	  This option is deprecated in favor of the <literal>sslmode</>
+	  setting.
+	 </para>
+	 <para>
+      If set to 1, an <acronym>SSL</acronym> connection to the server is required
+	  (this is equivalent to <literal>sslmode</> <literal>require</>).
       <application>libpq</> will then refuse to connect if the server does not
       accept an <acronym>SSL</acronym> connection.
-      If set to 0 (default), <application>libpq</> will negotiate the connection type with server.
+      If set to 0 (default), <application>libpq</> will negotiate the connection
+	  type with the server (equivalent to <literal>sslmode</> <literal>prefer</>).
       This option is only available if
       <productname>PostgreSQL</> is compiled with SSL support.
      </para>
@@ -3140,6 +3170,27 @@ the <productname>PostgreSQL</productname> server.
 </listitem>
 <listitem>
 <para>
+<indexterm>
+ <primary><envar>PGSSLMODE</envar></primary>
+</indexterm>
+<envar>PGSSLMODE</envar> determines whether and with what priority an
+<acronym>SSL</> connection will be negotiated with the server. There are
+four modes: <literal>disable</> will attempt only an unencrypted
+<acronym>SSL</> connection; <literal>allow</> will negotiate,
+trying first a non-<acronym>SSL</> connection, then if that fails,
+trying an <acronym>SSL</> connection; <literal>prefer</>
+(the default) will negotiate, trying first an <acronym>SSL</>
+connection, then if that fails, trying a regular non-<acronym>SSL</>
+connection; <literal>require</> will try only an <acronym>SSL</>
+connection. If <productname>PostgreSQL</> is compiled without SSL support,
+using option <literal>require</> will cause an error, and options
+<literal>allow</> and <literal>prefer</> will be tolerated but
+<application>libpq</> will be unable to negotiate an <acronym>SSL</>
+connection.
+</para>
+</listitem>
+<listitem>
+<para>
 <indexterm>
  <primary><envar>PGREQUIRESSL</envar></primary>
 </indexterm>
@@ -3147,8 +3198,10 @@ the <productname>PostgreSQL</productname> server.
 made over <acronym>SSL</acronym>. If set to
 <quote>1</quote>, <application>libpq</>
 will refuse to connect if the server does not accept
-an <acronym>SSL</acronym> connection.
-This option is only available if
+an <acronym>SSL</acronym> connection (equivalent to <literal>sslmode</>
+<literal>prefer</>).
+This option is deprecated in favor of the <literal>sslmode</>
+setting, and is only available if
 <productname>PostgreSQL</> is compiled with SSL support.
 </para>
 </listitem>
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index a24f0978466a126510b41053399fac4d62c58184..fd8d54a012db06e5c64cea309b9ac95e9e5f57e6 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.105 2003/07/23 23:30:40 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.106 2003/07/26 13:50:02 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -439,10 +439,16 @@ ClientAuthentication(Port *port)
 								NULL, 0,
 								NI_NUMERICHOST);
 
+#ifdef USE_SSL
+#define EREPORT_SSL_STATUS	(port->ssl ? "on" : "off")
+#else
+#define EREPORT_SSL_STATUS	"off"
+#endif
+
 				ereport(FATAL,
 						(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
-						 errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\"",
-								hostinfo, port->user_name, port->database_name)));
+						 errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", SSL \"%s\"",
+								hostinfo, port->user_name, port->database_name, EREPORT_SSL_STATUS)));
 				break;
 			}
 
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 0d98e729a40eb4e60cacd03a6636ef8e8b2a79fe..b233ee235d84139ef24cb905d2f429373def18b0 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.107 2003/07/23 23:30:40 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.108 2003/07/26 13:50:02 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -595,10 +595,12 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
 		if (port->raddr.addr.ss_family != AF_UNIX)
 			return;
 	}
-	else if (strcmp(token, "host") == 0 || strcmp(token, "hostssl") == 0)
+	else if (strcmp(token, "host") == 0
+			|| strcmp(token, "hostssl") == 0
+			|| strcmp(token, "hostnossl") == 0)
 	{
 
-		if (strcmp(token, "hostssl") == 0)
+		if (token[4] == 's')  /* "hostssl" */
 		{
 #ifdef USE_SSL
 			/* Record does not match if we are not on an SSL connection */
@@ -614,6 +616,14 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
 			goto hba_syntax;
 #endif
 		}
+#ifdef USE_SSL
+		else if (token[4] == 'n')  /* "hostnossl" */
+		{
+			/* Record does not match if we are on an SSL connection */
+			if (port->ssl)
+				return;
+		}
+#endif
 
 		/* Get the database. */
 		line = lnext(line);
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 0518cd21b4c75c070731a54e766f0ce72fb7afeb..6688e570381e1efd699101a73d94d28cc05fcfbb 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.253 2003/07/23 23:30:41 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.254 2003/07/26 13:50:02 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -60,6 +60,11 @@ long ioctlsocket_ret;
 #define DefaultOption	""
 #define DefaultAuthtype		  ""
 #define DefaultPassword		  ""
+#ifdef USE_SSL
+#define DefaultSSLMode	"prefer"
+#else
+#define DefaultSSLMode	"disable"
+#endif
 
 
 /* ----------
@@ -131,10 +136,22 @@ static const PQconninfoOption PQconninfoOptions[] = {
 	"Backend-Debug-Options", "D", 40},
 
 #ifdef USE_SSL
+	/*
+	 * "requiressl" is deprecated, its purpose having been taken over
+	 * by "sslmode". It remains for backwards compatibility.
+	 */
 	{"requiressl", "PGREQUIRESSL", "0", NULL,
-	"Require-SSL", "", 1},
+	"Require-SSL", "D", 1},
 #endif
 
+	/*
+	 * "sslmode" option is allowed even without client SSL support
+	 * because the client can still handle SSL modes "disable" and
+	 * "allow".
+	 */
+	{"sslmode", "PGSSLMODE", DefaultSSLMode, NULL,
+	"SSL-Mode", "", 8}, /* sizeof("disable") == 8 */
+
 	/* Terminating entry --- MUST BE LAST */
 	{NULL, NULL, NULL, NULL,
 	NULL, NULL, 0}
@@ -340,10 +357,17 @@ connectOptions1(PGconn *conn, const char *conninfo)
 	conn->pgpass = tmp ? strdup(tmp) : NULL;
 	tmp = conninfo_getval(connOptions, "connect_timeout");
 	conn->connect_timeout = tmp ? strdup(tmp) : NULL;
+	tmp = conninfo_getval(connOptions, "sslmode");
+	conn->sslmode = tmp ? strdup(tmp) : NULL;
 #ifdef USE_SSL
 	tmp = conninfo_getval(connOptions, "requiressl");
 	if (tmp && tmp[0] == '1')
-		conn->require_ssl = true;
+	{
+		/* here warn that the requiressl option is deprecated? */
+		if (conn->sslmode)
+			free(conn->sslmode);
+		conn->sslmode = "require";
+	}
 #endif
 
 	/*
@@ -412,6 +436,46 @@ connectOptions2(PGconn *conn)
 	}
 #endif
 
+	/*
+	 * validate sslmode option
+	 */
+	if (conn->sslmode)
+	{
+		if (strcmp(conn->sslmode, "disable") != 0
+			&& strcmp(conn->sslmode, "allow") != 0
+			&& strcmp(conn->sslmode, "prefer") != 0
+			&& strcmp(conn->sslmode, "require") != 0)
+		{
+			conn->status = CONNECTION_BAD;
+			printfPQExpBuffer(&conn->errorMessage,
+							  libpq_gettext("unknown sslmode \"%s\" requested\n"),
+							  conn->sslmode);
+			return false;
+		}
+
+#ifndef USE_SSL
+		switch (conn->sslmode[0]) {
+			case 'a': /* "allow" */
+			case 'p': /* "prefer" */
+				/*
+				 * warn user that an SSL connection will never be
+				 * negotiated since SSL was not compiled in?
+				 */
+				break;
+
+			case 'r': /* "require" */
+				conn->status = CONNECTION_BAD;
+				printfPQExpBuffer(&conn->errorMessage,
+								  libpq_gettext("sslmode \"%s\" invalid when SSL "
+												"support is not compiled in\n"),
+								  conn->sslmode);
+				return false;
+		}
+#endif
+	}
+	else
+		conn->sslmode = DefaultSSLMode;
+
 	return true;
 }
 
@@ -878,6 +942,14 @@ connectDBStart(PGconn *conn)
 		goto connect_errReturn;
 	}
 
+#ifdef USE_SSL
+	/* setup values based on SSL mode */
+	if (conn->sslmode[0] == 'd')  /* "disable" */
+		conn->allow_ssl_try = false;
+	else if (conn->sslmode[0] == 'a')  /* "allow" */
+		conn->wait_ssl_try = true;
+#endif
+
 	/*
 	 * Set up to try to connect, with protocol 3.0 as the first attempt.
 	 */
@@ -1278,9 +1350,8 @@ retry_connect:
 				{
 					/* Don't bother requesting SSL over a Unix socket */
 					conn->allow_ssl_try = false;
-					conn->require_ssl = false;
 				}
-				if (conn->allow_ssl_try && conn->ssl == NULL)
+				if (conn->allow_ssl_try && !conn->wait_ssl_try && conn->ssl == NULL)
 				{
 					ProtocolVersion pv;
 
@@ -1384,13 +1455,22 @@ retry_ssl_read:
 					}
 					else if (SSLok == 'N')
 					{
-						if (conn->require_ssl)
-						{
-							/* Require SSL, but server does not want it */
-							printfPQExpBuffer(&conn->errorMessage,
-											  libpq_gettext("server does not support SSL, but SSL was required\n"));
-							goto error_return;
+						switch (conn->sslmode[0]) {
+							case 'r':  /* "require" */
+								/* Require SSL, but server does not want it */
+								printfPQExpBuffer(&conn->errorMessage,
+												  libpq_gettext("server does not support SSL, but SSL was required\n"));
+								goto error_return;
+							case 'a':  /* "allow" */
+								/*
+								 * normal startup already failed,
+								 * so SSL failure means the end
+								 */
+								printfPQExpBuffer(&conn->errorMessage,
+												  libpq_gettext("server does not support SSL, and previous non-SSL attempt failed\n"));
+								goto error_return;
 						}
+
 						/* Otherwise, proceed with normal startup */
 						conn->allow_ssl_try = false;
 						conn->status = CONNECTION_MADE;
@@ -1401,13 +1481,22 @@ retry_ssl_read:
 						/* Received error - probably protocol mismatch */
 						if (conn->Pfdebug)
 							fprintf(conn->Pfdebug, "Postmaster reports error, attempting fallback to pre-7.0.\n");
-						if (conn->require_ssl)
-						{
-							/* Require SSL, but server is too old */
-							printfPQExpBuffer(&conn->errorMessage,
-											  libpq_gettext("server does not support SSL, but SSL was required\n"));
-							goto error_return;
+						switch (conn->sslmode[0]) {
+							case 'r':  /* "require" */
+								/* Require SSL, but server is too old */
+								printfPQExpBuffer(&conn->errorMessage,
+												  libpq_gettext("server does not support SSL, but SSL was required\n"));
+								goto error_return;
+							case 'a':  /* "allow" */
+								/*
+								 * normal startup already failed,
+								 * so SSL failure means the end
+								 */
+								printfPQExpBuffer(&conn->errorMessage,
+												  libpq_gettext("server does not support SSL, and previous non-SSL attempt failed\n"));
+								goto error_return;
 						}
+
 						/* Otherwise, try again without SSL */
 						conn->allow_ssl_try = false;
 						/* Assume it ain't gonna handle protocol 3, either */
@@ -1594,6 +1683,45 @@ retry_ssl_read:
 					}
 					/* OK, we read the message; mark data consumed */
 					conn->inStart = conn->inCursor;
+
+#ifdef USE_SSL
+					/*
+					 * if sslmode is "allow" and we haven't tried an
+					 * SSL connection already, then retry with an SSL connection
+					 */
+					if (conn->wait_ssl_try
+						&& conn->ssl == NULL
+						&& conn->allow_ssl_try)
+					{
+						conn->wait_ssl_try = false;
+						/* Must drop the old connection */
+						closesocket(conn->sock);
+						conn->sock = -1;
+						conn->status = CONNECTION_NEEDED;
+						goto keep_going;
+					}
+
+					/*
+					 * if sslmode is "prefer" and we're in an SSL
+					 * connection and we haven't already tried a non-SSL
+					 * for "allow", then do a non-SSL retry
+					 */
+					if (!conn->wait_ssl_try
+						&& conn->ssl
+						&& conn->allow_ssl_try
+						&& conn->sslmode[0] == 'p')  /* "prefer" */
+					{
+						conn->allow_ssl_try = false;
+						/* Must drop the old connection */
+						pqsecure_close(conn);
+						closesocket(conn->sock);
+						conn->sock = -1;
+						free(conn->ssl);
+						conn->status = CONNECTION_NEEDED;
+						goto keep_going;
+					}
+#endif
+
 					goto error_return;
 				}
 
@@ -1645,6 +1773,44 @@ retry_ssl_read:
 				if (fe_sendauth(areq, conn, conn->pghost, conn->pgpass,
 								conn->errorMessage.data) != STATUS_OK)
 				{
+#ifdef USE_SSL
+					/*
+					 * if sslmode is "allow" and we haven't tried an
+					 * SSL connection already, then retry with an SSL connection
+					 */
+					if (conn->wait_ssl_try
+						&& conn->ssl == NULL
+						&& conn->allow_ssl_try)
+					{
+						conn->wait_ssl_try = false;
+						/* Must drop the old connection */
+						closesocket(conn->sock);
+						conn->sock = -1;
+						conn->status = CONNECTION_NEEDED;
+						goto keep_going;
+					}
+
+					/*
+					 * if sslmode is "prefer" and we're in an SSL
+					 * connection and we haven't already tried a non-SSL
+					 * for "allow", then do a non-SSL retry
+					 */
+					if (!conn->wait_ssl_try
+						&& conn->ssl
+						&& conn->allow_ssl_try
+						&& conn->sslmode[0] == 'p')  /* "prefer" */
+					{
+						conn->allow_ssl_try = false;
+						/* Must drop the old connection */
+						pqsecure_close(conn);
+						closesocket(conn->sock);
+						conn->sock = -1;
+						free(conn->ssl);
+						conn->status = CONNECTION_NEEDED;
+						goto keep_going;
+					}
+#endif
+
 					conn->errorMessage.len = strlen(conn->errorMessage.data);
 					goto error_return;
 				}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index d97db7c88b1189220fbba05b0020cb8b055f8709..d05681d37f03887ef2cd54d83d16a0f7fe5d9d90 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: libpq-int.h,v 1.76 2003/06/23 19:20:25 tgl Exp $
+ * $Id: libpq-int.h,v 1.77 2003/07/26 13:50:02 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -316,9 +316,11 @@ struct pg_conn
 	PGresult   *result;			/* result being constructed */
 	PGresAttValue *curTuple;	/* tuple currently being read */
 
+	char	   *sslmode;		/* SSL mode option string */
 #ifdef USE_SSL
 	bool		allow_ssl_try;	/* Allowed to try SSL negotiation */
-	bool		require_ssl;	/* Require SSL to make connection */
+	bool		wait_ssl_try;	/* Delay SSL negotiation until after
+								   attempting normal connection */
 	SSL		   *ssl;			/* SSL status, if have SSL connection */
 	X509	   *peer;			/* X509 cert of server */
 	char		peer_dn[256 + 1];		/* peer distinguished name */