diff --git a/doc/src/sgml/ref/wait.sgml b/doc/src/sgml/ref/wait.sgml
index 2917309c..c7d594a9 100644
--- a/doc/src/sgml/ref/wait.sgml
+++ b/doc/src/sgml/ref/wait.sgml
@@ -161,6 +161,9 @@ WAIT FOR LSN '<replaceable class="parameter">lsn</replaceable>'
           less therefore rounds down to zero, which means waiting
           indefinitely.
          </para>
+         <para>
+          Negative timeout values are rejected with an error.
+         </para>
         </listitem>
        </varlistentry>
 
diff --git a/src/backend/commands/wait.c b/src/backend/commands/wait.c
index a609f637..bd2aad90 100644
--- a/src/backend/commands/wait.c
+++ b/src/backend/commands/wait.c
@@ -13,6 +13,8 @@
  */
 #include "postgres.h"
 
+#include <ctype.h>
+
 #include "access/xact.h"
 #include "access/xlog.h"
 #include "access/xlogrecovery.h"
@@ -107,6 +109,28 @@ ExecWaitStmt(ParseState *pstate, WaitStmt *stmt, bool isTopLevel,
 						hintmsg ? errhint("%s", _(hintmsg)) : 0,
 						parser_errposition(pstate, defel->location));
 
+			/*
+			 * parse_int() rounds fractional values to integer before we
+			 * get a chance to check them, so a negative timeout smaller
+			 * than half a millisecond (e.g. '-0.4ms') would otherwise
+			 * round to zero and silently become an infinite wait.  Reject
+			 * any negative input up front: parse_int() accepts the sign
+			 * syntaxes of strtol()/strtod(), where a negative value
+			 * necessarily starts with a '-'.
+			 */
+			{
+				const char *cp = timeout_str;
+
+				while (isspace((unsigned char) *cp))
+					cp++;
+
+				if (*cp == '-')
+					ereport(ERROR,
+							errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+							errmsg("timeout cannot be negative"),
+							parser_errposition(pstate, defel->location));
+			}
+
 			if (timeout < 0)
 				ereport(ERROR,
 						errcode(ERRCODE_INVALID_PARAMETER_VALUE),
diff --git a/src/test/recovery/t/049_wait_for_lsn.pl b/src/test/recovery/t/049_wait_for_lsn.pl
index 0fe5b9c6..ea9eefe2 100644
--- a/src/test/recovery/t/049_wait_for_lsn.pl
+++ b/src/test/recovery/t/049_wait_for_lsn.pl
@@ -367,6 +367,25 @@ $node_standby->psql(
 	stderr => \$stderr);
 ok($stderr =~ /timeout cannot be negative/, "get error for negative timeout");
 
+# Test negative sub-millisecond timeout: rint() would round these to zero
+# before the < 0 check, silently turning them into an infinite wait
+for my $neg_timeout (qw(-0.4ms -0.49ms -0.4999999ms -0.000001s -0))
+{
+	$node_standby->psql(
+		'postgres',
+		"WAIT FOR LSN '${test_lsn}' WITH (timeout '${neg_timeout}');",
+		stderr => \$stderr);
+	ok($stderr =~ /timeout cannot be negative/,
+		"get error for negative sub-millisecond timeout '${neg_timeout}'");
+
+	$node_standby->psql(
+		'postgres',
+		"WAIT FOR LSN '${test_lsn}' WITH (timeout ' ${neg_timeout} ');",
+		stderr => \$stderr);
+	ok($stderr =~ /timeout cannot be negative/,
+		"get error for negative timeout '${neg_timeout}' with leading space");
+}
+
 # Test out of range timeout
 $node_standby->psql(
 	'postgres',
