diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 49de975e7f..94d114562a 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1579,6 +1579,16 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
     </varlistentry>
     </variablelist>
    </para>
+
+   <para>
+    Integer values expected for keywords <literal>port</literal>,
+    <literal>connect_timeout</literal>,
+    <literal>keepalives_idle</literal>,
+    <literal>keepalives_interval</literal> and
+    <literal>keepalives_timeout</literal> are parsed strictly.
+    Versions of <application>libpq</application> before
+    <product>PostgreSQL 12</product> accepted trailing garbage or overflows.
+   </para>
   </sect2>
  </sect1>
 
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 9315a27561..15280dc208 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -1586,6 +1586,35 @@ useKeepalives(PGconn *conn)
 	return val != 0 ? 1 : 0;
 }
 
+/*
+ * Parse integer, report any syntax error, and tell if all is well.
+ */
+static bool
+strict_atoi(const char *str, int *val, PGconn *conn, const char *context)
+{
+	char 	*endptr;
+
+	errno = 0;
+	*val = strtol(str, &endptr, 10);
+
+	if (errno != 0)
+	{
+		appendPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("invalid integer \"%s\" for keyword \"%s\": %s\n"),
+						  str, context, strerror(errno));
+		return false;
+	}
+	else if (*endptr != '\0')
+	{
+		appendPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("invalid integer \"%s\" for keyword \"%s\"\n"),
+						  str, context);
+		return false;
+	}
+
+	return true;
+}
+
 #ifndef WIN32
 /*
  * Set the keepalive idle timer.
@@ -1598,7 +1627,9 @@ setKeepalivesIdle(PGconn *conn)
 	if (conn->keepalives_idle == NULL)
 		return 1;
 
-	idle = atoi(conn->keepalives_idle);
+	if (!strict_atoi(conn->keepalives_idle, &idle, conn, "keepalives_idle"))
+		return 0;
+
 	if (idle < 0)
 		idle = 0;
 
@@ -1630,7 +1661,9 @@ setKeepalivesInterval(PGconn *conn)
 	if (conn->keepalives_interval == NULL)
 		return 1;
 
-	interval = atoi(conn->keepalives_interval);
+	if (!strict_atoi(conn->keepalives_interval, &interval, conn, "keepalives_interval"))
+		return 0;
+
 	if (interval < 0)
 		interval = 0;
 
@@ -1663,7 +1696,9 @@ setKeepalivesCount(PGconn *conn)
 	if (conn->keepalives_count == NULL)
 		return 1;
 
-	count = atoi(conn->keepalives_count);
+	if (!strict_atoi(conn->keepalives_count, &count, conn, "keepalives_count"))
+		return 0;
+
 	if (count < 0)
 		count = 0;
 
@@ -1697,13 +1732,17 @@ setKeepalivesWin32(PGconn *conn)
 	int			idle = 0;
 	int			interval = 0;
 
-	if (conn->keepalives_idle)
-		idle = atoi(conn->keepalives_idle);
+	if (conn->keepalives_idle &&
+		!strict_atoi(conn->keepalives_idle, &idle, conn, "keepalives_idle"))
+		return 0;
+
+	if (conn->keepalives_interval &&
+		!strict_atoi(conn->keepalives_interval, &interval, conn, "keepalives_interval"))
+		return 0;
+
 	if (idle <= 0)
 		idle = 2 * 60 * 60;		/* 2 hours = default */
 
-	if (conn->keepalives_interval)
-		interval = atoi(conn->keepalives_interval);
 	if (interval <= 0)
 		interval = 1;			/* 1 second = default */
 
@@ -1784,7 +1823,9 @@ connectDBStart(PGconn *conn)
 			thisport = DEF_PGPORT;
 		else
 		{
-			thisport = atoi(ch->port);
+			if (!strict_atoi(ch->port, &thisport, conn, "port"))
+				goto connect_errReturn;
+
 			if (thisport < 1 || thisport > 65535)
 			{
 				appendPQExpBuffer(&conn->errorMessage,
@@ -1916,7 +1957,9 @@ connectDBComplete(PGconn *conn)
 	 */
 	if (conn->connect_timeout != NULL)
 	{
-		timeout = atoi(conn->connect_timeout);
+		if (!strict_atoi(conn->connect_timeout, &timeout, conn, "connect_timeout"))
+			return 0;
+
 		if (timeout > 0)
 		{
 			/*
@@ -1927,6 +1970,8 @@ connectDBComplete(PGconn *conn)
 			if (timeout < 2)
 				timeout = 2;
 		}
+		else /* negative means 0 */
+			timeout = 0;
 	}
 
 	for (;;)
