diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml
index e3a0abb4c7..a6370f00dd 100644
*** a/doc/src/sgml/ref/pgbench.sgml
--- b/doc/src/sgml/ref/pgbench.sgml
***************
*** 193,204 **** pgbench <optional> <replaceable>options</replaceable> </optional> <replaceable>d
            </listitem>
           </varlistentry>
           <varlistentry>
!           <term><literal>g</literal> (Generate data)</term>
            <listitem>
             <para>
              Generate data and load it into the standard tables,
              replacing any data already present.
             </para>
            </listitem>
           </varlistentry>
           <varlistentry>
--- 193,226 ----
            </listitem>
           </varlistentry>
           <varlistentry>
!           <term><literal>g</literal> or <literal>G</literal> (Generate data, client-side or server-side)</term>
            <listitem>
             <para>
              Generate data and load it into the standard tables,
              replacing any data already present.
             </para>
+            <para>
+             With <literal>g</literal> (client-side data generation),
+             data is generated in <command>pgbench</command> client and then
+             sent to the server. This uses the client/server bandwidth
+             extensively through a <command>COPY</command>.
+             Using <literal>g</literal> causes logging to print one message
+             each 100,000 rows when generating data into
+             <structname>pgbench_accounts</structname> table.
+            </para>
+            <para>
+             With <literal>G</literal> (server-side data generation),
+             only limited queries are sent from <command>pgbench</command>
+             client and then data is actually generated in the server.
+             No significant bandwidth is required for this variant, but
+             the server will do more work.
+             Using <literal>G</literal> causes logging to print no progress
+             message when generating data into
+             <structname>pgbench_accounts</structname> table.
+            </para>
+            <para>
+             
+            </para>
            </listitem>
           </varlistentry>
           <varlistentry>
***************
*** 262,270 **** pgbench <optional> <replaceable>options</replaceable> </optional> <replaceable>d
        <listitem>
         <para>
          Switch logging to quiet mode, producing only one progress message per 5
!         seconds. The default logging prints one message each 100000 rows, which
          often outputs many lines per second (especially on good hardware).
         </para>
        </listitem>
       </varlistentry>
  
--- 284,296 ----
        <listitem>
         <para>
          Switch logging to quiet mode, producing only one progress message per 5
!         seconds. The default logging prints one message each 100,000 rows, which
          often outputs many lines per second (especially on good hardware).
         </para>
+        <para>
+         This setting has no effect if <literal>G</literal> is specified
+         in <option>-I</option>.
+        </para>
        </listitem>
       </varlistentry>
  
diff --git a/src/bin/pgbench/pgbenchindex 03bcd22996..14dbc4510c 100644
*** a/src/bin/pgbench/pgbench.c
--- b/src/bin/pgbench/pgbench.c
***************
*** 132,137 **** static int	pthread_join(pthread_t th, void **thread_return);
--- 132,138 ----
   * some configurable parameters */
  
  #define DEFAULT_INIT_STEPS "dtgvp"	/* default -I setting */
+ #define ALL_INIT_STEPS "dtgGvpf"	/* all possible steps */
  
  #define LOG_STEP_SECONDS	5	/* seconds between log messages */
  #define DEFAULT_NXACTS	10		/* default nxacts */
***************
*** 627,633 **** usage(void)
  		   "  %s [OPTION]... [DBNAME]\n"
  		   "\nInitialization options:\n"
  		   "  -i, --initialize         invokes initialization mode\n"
! 		   "  -I, --init-steps=[dtgvpf]+ (default \"dtgvp\")\n"
  		   "                           run selected initialization steps\n"
  		   "  -F, --fillfactor=NUM     set fill factor\n"
  		   "  -n, --no-vacuum          do not run VACUUM during initialization\n"
--- 628,634 ----
  		   "  %s [OPTION]... [DBNAME]\n"
  		   "\nInitialization options:\n"
  		   "  -i, --initialize         invokes initialization mode\n"
! 		   "  -I, --init-steps=[" ALL_INIT_STEPS "]+ (default \"" DEFAULT_INIT_STEPS "\")\n"
  		   "                           run selected initialization steps\n"
  		   "  -F, --fillfactor=NUM     set fill factor\n"
  		   "  -n, --no-vacuum          do not run VACUUM during initialization\n"
***************
*** 3803,3812 **** append_fillfactor(char *opts, int len)
  }
  
  /*
!  * Fill the standard tables with some data
   */
  static void
! initGenerateData(PGconn *con)
  {
  	char		sql[256];
  	PGresult   *res;
--- 3804,3826 ----
  }
  
  /*
!  * Truncate away any old data, in one command in case there are foreign keys
   */
  static void
! initTruncateTables(PGconn *con)
! {
! 	executeStatement(con, "truncate table "
! 					 "pgbench_accounts, "
! 					 "pgbench_branches, "
! 					 "pgbench_history, "
! 					 "pgbench_tellers");
! }
! 
! /*
!  * Fill the standard tables with some data generated and sent from the client
!  */
! static void
! initGenerateDataClientSide(PGconn *con)
  {
  	char		sql[256];
  	PGresult   *res;
***************
*** 3820,3826 **** initGenerateData(PGconn *con)
  				remaining_sec;
  	int			log_interval = 1;
  
! 	fprintf(stderr, "generating data...\n");
  
  	/*
  	 * we do all of this in one transaction to enable the backend's
--- 3834,3840 ----
  				remaining_sec;
  	int			log_interval = 1;
  
! 	fprintf(stderr, "generating data (client-side)...\n");
  
  	/*
  	 * we do all of this in one transaction to enable the backend's
***************
*** 3828,3842 **** initGenerateData(PGconn *con)
  	 */
  	executeStatement(con, "begin");
  
! 	/*
! 	 * truncate away any old data, in one command in case there are foreign
! 	 * keys
! 	 */
! 	executeStatement(con, "truncate table "
! 					 "pgbench_accounts, "
! 					 "pgbench_branches, "
! 					 "pgbench_history, "
! 					 "pgbench_tellers");
  
  	/*
  	 * fill branches, tellers, accounts in that order in case foreign keys
--- 3842,3849 ----
  	 */
  	executeStatement(con, "begin");
  
! 	/* truncate away any old data */
! 	initTruncateTables(con);
  
  	/*
  	 * fill branches, tellers, accounts in that order in case foreign keys
***************
*** 3940,3945 **** initGenerateData(PGconn *con)
--- 3947,3997 ----
  	executeStatement(con, "commit");
  }
  
+ /*
+  * Fill the standard tables with some data generated on the server
+  *
+  * As already the case with the client-side data generation, the filler
+  * column defaults to NULL in pgbench_branches and pgbench_tellers,
+  * and is a blank-padded string in pgbench_accounts.
+  */
+ static void
+ initGenerateDataServerSide(PGconn *con)
+ {
+ 	char		sql[256];
+ 
+ 	fprintf(stderr, "generating data (server-side)...\n");
+ 
+ 	/*
+ 	 * we do all of this in one transaction to enable the backend's
+ 	 * data-loading optimizations
+ 	 */
+ 	executeStatement(con, "begin");
+ 
+ 	/* truncate away any old data */
+ 	initTruncateTables(con);
+ 
+ 	snprintf(sql, sizeof(sql),
+ 			 "insert into pgbench_branches(bid,bbalance) "
+ 			 "select bid, 0 "
+ 			 "from generate_series(1, %d) as bid", nbranches * scale);
+ 	executeStatement(con, sql);
+ 
+ 	snprintf(sql, sizeof(sql),
+ 			 "insert into pgbench_tellers(tid,bid,tbalance) "
+ 			 "select tid, (tid - 1) / %d + 1, 0 "
+ 			 "from generate_series(1, %d) as tid", ntellers, ntellers * scale);
+ 	executeStatement(con, sql);
+ 
+ 	snprintf(sql, sizeof(sql),
+ 			 "insert into pgbench_accounts(aid,bid,abalance,filler) "
+ 			 "select aid, (aid - 1) / %d + 1, 0, '' "
+ 			 "from generate_series(1, "INT64_FORMAT") as aid",
+ 			 naccounts, (int64) naccounts * scale);
+ 	executeStatement(con, sql);
+ 
+ 	executeStatement(con, "commit");
+ }
+ 
  /*
   * Invoke vacuum on the standard tables
   */
***************
*** 4020,4040 **** initCreateFKeys(PGconn *con)
  static void
  checkInitSteps(const char *initialize_steps)
  {
- 	const char *step;
- 
  	if (initialize_steps[0] == '\0')
  	{
  		fprintf(stderr, "no initialization steps specified\n");
  		exit(1);
  	}
  
! 	for (step = initialize_steps; *step != '\0'; step++)
  	{
! 		if (strchr("dtgvpf ", *step) == NULL)
  		{
! 			fprintf(stderr, "unrecognized initialization step \"%c\"\n",
  					*step);
! 			fprintf(stderr, "allowed steps are: \"d\", \"t\", \"g\", \"v\", \"p\", \"f\"\n");
  			exit(1);
  		}
  	}
--- 4072,4092 ----
  static void
  checkInitSteps(const char *initialize_steps)
  {
  	if (initialize_steps[0] == '\0')
  	{
  		fprintf(stderr, "no initialization steps specified\n");
  		exit(1);
  	}
  
! 	for (const char *step = initialize_steps; *step != '\0'; step++)
  	{
! 		if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
  		{
! 			fprintf(stderr,
! 					"unrecognized initialization step \"%c\"\n",
  					*step);
! 			fprintf(stderr,
! 					"Allowed step characters are: \"" ALL_INIT_STEPS "\".\n");
  			exit(1);
  		}
  	}
***************
*** 4075,4082 **** runInitSteps(const char *initialize_steps)
  				initCreateTables(con);
  				break;
  			case 'g':
! 				op = "generate";
! 				initGenerateData(con);
  				break;
  			case 'v':
  				op = "vacuum";
--- 4127,4138 ----
  				initCreateTables(con);
  				break;
  			case 'g':
! 				op = "client-side generate";
! 				initGenerateDataClientSide(con);
! 				break;
! 			case 'G':
! 				op = "server-side generate";
! 				initGenerateDataServerSide(con);
  				break;
  			case 'v':
  				op = "vacuum";
diff --git a/src/bin/pgbench/t/0index c441626d7c..1845869016 100644
*** a/src/bin/pgbench/t/001_pgbench_with_server.pl
--- b/src/bin/pgbench/t/001_pgbench_with_server.pl
***************
*** 130,136 **** pgbench(
  
  # Test interaction of --init-steps with legacy step-selection options
  pgbench(
! 	'--initialize --init-steps=dtpvgvv --no-vacuum --foreign-keys --unlogged-tables --partitions=3',
  	0,
  	[qr{^$}],
  	[
--- 130,136 ----
  
  # Test interaction of --init-steps with legacy step-selection options
  pgbench(
! 	'--initialize --init-steps=dtpvGvv --no-vacuum --foreign-keys --unlogged-tables --partitions=3',
  	0,
  	[qr{^$}],
  	[
***************
*** 138,144 **** pgbench(
  		qr{creating tables},
  		qr{creating 3 partitions},
  		qr{creating primary keys},
! 		qr{.* of .* tuples \(.*\) done},
  		qr{creating foreign keys},
  		qr{(?!vacuuming)}, # no vacuum
  		qr{done in \d+\.\d\d s }
--- 138,144 ----
  		qr{creating tables},
  		qr{creating 3 partitions},
  		qr{creating primary keys},
! 		qr{generating data \(server-side\)},
  		qr{creating foreign keys},
  		qr{(?!vacuuming)}, # no vacuum
  		qr{done in \d+\.\d\d s }
diff --git a/src/bin/pgbench/t/002_pgbench_no_serveindex 1e9542af3f..8b6d442812 100644
*** a/src/bin/pgbench/t/002_pgbench_no_server.pl
--- b/src/bin/pgbench/t/002_pgbench_no_server.pl
***************
*** 147,153 **** my @options = (
  	[
  		'invalid init step',
  		'-i -I dta',
! 		[ qr{unrecognized initialization step}, qr{allowed steps are} ]
  	],
  	[
  		'bad random seed',
--- 147,153 ----
  	[
  		'invalid init step',
  		'-i -I dta',
! 		[ qr{unrecognized initialization step}, qr{Allowed step characters are} ]
  	],
  	[
  		'bad random seed',
