diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index 08a5947a9e..2cd698c027 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -27,10 +27,6 @@
  *
  */
 
-#ifdef WIN32
-#define FD_SETSIZE 1024			/* must set before winsock2.h is included */
-#endif
-
 #include "postgres_fe.h"
 
 #include <ctype.h>
@@ -6698,16 +6694,30 @@ 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.
+ *
+ * FD_SETSIZE is defined to 64 by default on windows.
+ */
+#define FD_IS_VALID(fd, set) ((fd) >= 0 && (set)->fd_count < FD_SETSIZE)
+#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
 		 * complicating the API to make it less grotty.
 		 */
-		pg_log_fatal("too many client connections for select()");
+		pg_log_fatal("too many client connections for select(), consider using more threads");
 		exit(1);
 	}
 	FD_SET(fd, &sa->fds);
