diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index 08a5947a9e..f94a13750c 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -6698,10 +6698,26 @@ clear_socket_set(socket_set *sa)
 	sa->maxfd = -1;
 }
 
+#ifndef WIN32
+#define FD_IS_VALID(fd, set) ((fd) >= 0 && (fd) < FD_SETSIZE)
+#else
+/*
+ * Windows implementation is bogus: it does not allocate fd with the lowest
+ * possible number, and FD_SET is implemented as a simple array.
+ *
+ * Filling the set is in O(N^2) because of deduplication, but this is
+ * unnecessary here so we just override the macro.
+ */
+#define FD_IS_VALID(fd, set) ((fd) >= 0 && (set)->fd_count < FD_SETSIZE)
+#undef FD_SET
+/* no array overflow if FD_IS_VALID is ok */
+#define FD_SET(fd, set) (set)->fd_array[(set)->fd_count++] = (fd)
+#endif /* WIN32 */
+
 static void
 add_socket_to_set(socket_set *sa, int fd, int idx)
 {
-	if (fd < 0 || fd >= FD_SETSIZE)
+	if (!FD_IS_VALID(fd, &sa->fds))
 	{
 		/*
 		 * Doing a hard exit here is a bit grotty, but it doesn't seem worth
