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 'lsn'
less therefore rounds down to zero, which means waiting
indefinitely.
+
+ Negative timeout values are rejected with an error.
+
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
+
#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',