diff --git a/src/bin/pg_dump/t/010_dump_connstr.pl b/src/bin/pg_dump/t/010_dump_connstr.pl
new file mode 100644
index 0000000000000000000000000000000000000000..2d0d1e4298e0e1b486bb46fe4c5753b3e05b1983
--- /dev/null
+++ b/src/bin/pg_dump/t/010_dump_connstr.pl
@@ -0,0 +1,142 @@
+use strict;
+use warnings;
+
+use PostgresNode;
+use TestLib;
+use Test::More tests => 14;
+
+# In a SQL_ASCII database, pgwin32_message_to_UTF16() needs to
+# interpret everything as UTF8.  We're going to use byte sequences
+# that aren't valid UTF-8 strings, so that would fail.  Use LATIN1,
+# which accepts any byte and has a conversion from each byte to UTF-8.
+$ENV{LC_ALL} = 'C';
+$ENV{PGCLIENTENCODING} = 'LATIN1';
+
+# Create database and user names covering the range of LATIN1
+# characters, for use in a connection string by pg_dumpall.  Skip ','
+# because of pg_regress --create-role, skip [\n\r] because pg_dumpall
+# does not allow them.
+my $dbname1 = generate_ascii_string(1, 9) .
+	generate_ascii_string(11, 12) .
+	generate_ascii_string(14, 33) .
+	($TestLib::windows_os ? '' : '"x"') .  # IPC::Run mishandles '"' on Windows
+	generate_ascii_string(35, 43) .
+	generate_ascii_string(45, 63);  # contains '='
+my $dbname2 = generate_ascii_string(67, 129);  # skip 64-66 to keep length to 62
+my $dbname3 = generate_ascii_string(130, 192);
+my $dbname4 = generate_ascii_string(193, 255);
+
+my $node = get_new_node('main');
+$node->init(extra => ['--locale=C', '--encoding=LATIN1']);
+# prep pg_hba.conf and pg_ident.conf
+$node->run_log([$ENV{PG_REGRESS}, '--config-auth', $node->data_dir,
+				'--create-role', "$dbname1,$dbname2,$dbname3,$dbname4"]);
+$node->start;
+
+my $backupdir = $node->backup_dir;
+my $discard = "$backupdir/discard.sql";
+my $plain = "$backupdir/plain.sql";
+my $dirfmt = "$backupdir/dirfmt";
+
+foreach my $dbname ($dbname1, $dbname2, $dbname3, $dbname4, 'CamelCase')
+{
+	$node->run_log(['createdb', $dbname]);
+	$node->run_log(['createuser', '-s', $dbname]);
+}
+
+
+# For these tests, pg_dumpall -r is used because it produces a short
+# dump.
+$node->command_ok(['pg_dumpall', '-r', '-f', $discard, '--dbname',
+				   $node->connstr($dbname1), '-U', $dbname4],
+				  'pg_dumpall with long ASCII name 1');
+$node->command_ok(['pg_dumpall', '-r', '-f', $discard, '--dbname',
+				   $node->connstr($dbname2), '-U', $dbname3],
+				  'pg_dumpall with long ASCII name 2');
+$node->command_ok(['pg_dumpall', '-r', '-f', $discard,  '--dbname',
+				   $node->connstr($dbname3), '-U', $dbname2],
+				  'pg_dumpall with long ASCII name 3');
+$node->command_ok(['pg_dumpall', '-r', '-f', $discard,  '--dbname',
+				   $node->connstr($dbname4), '-U', $dbname1],
+				  'pg_dumpall with long ASCII name 4');
+$node->command_ok(['pg_dumpall', '-r', '-l', 'dbname=template1'],
+				  'pg_dumpall -l accepts connection string');
+
+$node->run_log(['createdb', "foo\n\rbar"]);
+# not sufficient to use -r here
+$node->command_fails(['pg_dumpall', '-f', $discard],
+					 'pg_dumpall with \n\r in database name');
+$node->run_log(['dropdb', "foo\n\rbar"]);
+
+
+# make a table, so the parallel worker has something to dump
+$node->safe_psql($dbname1, 'CREATE TABLE t0()');
+# XXX no printed message when this fails, just SIGPIPE termination
+$node->command_ok(['pg_dump', '-Fd', '-j2', '-f', $dirfmt,
+				   '-U', $dbname1, $node->connstr($dbname1)],
+				  'parallel dump');
+
+# recreate $dbname1 for restore test
+$node->run_log(['dropdb', $dbname1]);
+$node->run_log(['createdb', $dbname1]);
+
+$node->command_ok(['pg_restore', '-v', '-d', 'template1', '-j2',
+				   '-U', $dbname1, $dirfmt],
+				  'parallel restore');
+
+$node->run_log(['dropdb', $dbname1]);
+
+$node->command_ok(['pg_restore', '-C', '-v', '-d', 'template1', '-j2',
+				   '-U', $dbname1, $dirfmt],
+				  'parallel restore with create');
+
+
+$node->command_ok(['pg_dumpall', '-f', $plain, '-U', $dbname1],
+				  'take full dump');
+system_log('cat', $plain);
+my($stderr, $result);
+my $bootstrap_super = 'boot';
+my $restore_super = qq{a'b\\c=d\\ne"f};
+
+
+# Restore full dump through psql using environment variables for
+# dbname/user connection parameters
+
+my $envar_node = get_new_node('destination_envar');
+$envar_node->init(extra => ['-U', $bootstrap_super,
+							'--locale=C', '--encoding=LATIN1']);
+$envar_node->run_log([$ENV{PG_REGRESS},
+					  '--config-auth', $envar_node->data_dir,
+					  '--create-role', "$bootstrap_super,$restore_super"]);
+$envar_node->start;
+
+# make superuser for restore
+$envar_node->run_log(['createuser', '-U', $bootstrap_super, '-s', $restore_super]);
+
+{
+	local $ENV{PGPORT} = $envar_node->port;
+	local $ENV{PGUSER} = $restore_super;
+	$result = run_log(['psql', '-X', '-f', $plain], '2>', \$stderr);
+}
+ok($result, 'restore full dump using environment variables for connection parameters');
+is($stderr, '', 'no dump errors');
+
+
+# Restore full dump through psql using command-line options for
+# dbname/user connection parameters.  "\connect dbname=" forgets
+# user/port from command line.
+
+$restore_super =~ s/"//g if $TestLib::windows_os;  # IPC::Run mishandles '"' on Windows
+my $cmdline_node = get_new_node('destination_cmdline');
+$cmdline_node->init(extra => ['-U', $bootstrap_super,
+							  '--locale=C', '--encoding=LATIN1']);
+$cmdline_node->run_log([$ENV{PG_REGRESS},
+						'--config-auth', $cmdline_node->data_dir,
+						'--create-role', "$bootstrap_super,$restore_super"]);
+$cmdline_node->start;
+$cmdline_node->run_log(['createuser', '-U', $bootstrap_super, '-s', $restore_super]);
+{
+	$result = run_log(['psql', '-p', $cmdline_node->port, '-U', $restore_super, '-X', '-f', $plain], '2>', \$stderr);
+}
+ok($result, 'restore full dump with command-line options for connection parameters');
+is($stderr, '', 'no dump errors');
diff --git a/src/bin/pg_rewind/RewindTest.pm b/src/bin/pg_rewind/RewindTest.pm
index 135d8f0449f596cf86e8a43809356b78b0b2d4ea..c7c3a8f45c6abe8b05006d899fcf885ecfd6934c 100644
--- a/src/bin/pg_rewind/RewindTest.pm
+++ b/src/bin/pg_rewind/RewindTest.pm
@@ -133,7 +133,7 @@ sub create_standby
 	$node_standby = get_new_node('standby');
 	$node_master->backup('my_backup');
 	$node_standby->init_from_backup($node_master, 'my_backup');
-	my $connstr_master = $node_master->connstr('postgres');
+	my $connstr_master = $node_master->connstr();
 
 	$node_standby->append_conf(
 		"recovery.conf", qq(
diff --git a/src/bin/scripts/t/010_clusterdb.pl b/src/bin/scripts/t/010_clusterdb.pl
index 0e677cacf18cc51cfd9e74365467eb08e2ccf117..f3de9c016cee7176593f0777476f2a232eef5645 100644
--- a/src/bin/scripts/t/010_clusterdb.pl
+++ b/src/bin/scripts/t/010_clusterdb.pl
@@ -3,7 +3,7 @@ use warnings;
 
 use PostgresNode;
 use TestLib;
-use Test::More tests => 13;
+use Test::More tests => 14;
 
 program_help_ok('clusterdb');
 program_version_ok('clusterdb');
@@ -28,3 +28,6 @@ $node->issues_sql_like(
 	[ 'clusterdb', '-t', 'test1' ],
 	qr/statement: CLUSTER test1;/,
 	'cluster specific table');
+
+$node->command_ok([qw(clusterdb --echo --verbose dbname=template1)],
+				  'clusterdb with connection string');
diff --git a/src/bin/scripts/t/090_reindexdb.pl b/src/bin/scripts/t/090_reindexdb.pl
index d92896f34f6ae3f5eedc3e54758266654671f590..42d6fb4eb456c3c4353446d129a2a89ec552f483 100644
--- a/src/bin/scripts/t/090_reindexdb.pl
+++ b/src/bin/scripts/t/090_reindexdb.pl
@@ -3,7 +3,7 @@ use warnings;
 
 use PostgresNode;
 use TestLib;
-use Test::More tests => 20;
+use Test::More tests => 23;
 
 program_help_ok('reindexdb');
 program_version_ok('reindexdb');
@@ -42,3 +42,10 @@ $node->issues_sql_like(
 	[ 'reindexdb', '-v', '-t', 'test1', 'postgres' ],
 	qr/statement: REINDEX \(VERBOSE\) TABLE test1;/,
 	'reindex with verbose output');
+
+$node->command_ok([qw(reindexdb --echo --table=pg_am dbname=template1)],
+				  'reindexdb table with connection string');
+$node->command_ok([qw(reindexdb --echo dbname=template1)],
+				  'reindexdb database with connection string');
+$node->command_ok([qw(reindexdb --echo --system dbname=template1)],
+				  'reindexdb system with connection string');
diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl
index c183ccb6a1903ae3e5fea77c657b46b334cd4179..07c6e9e7ce136a61dd1ccf0430b081d93aae4973 100644
--- a/src/bin/scripts/t/100_vacuumdb.pl
+++ b/src/bin/scripts/t/100_vacuumdb.pl
@@ -3,7 +3,7 @@ use warnings;
 
 use PostgresNode;
 use TestLib;
-use Test::More tests => 18;
+use Test::More tests => 19;
 
 program_help_ok('vacuumdb');
 program_version_ok('vacuumdb');
@@ -33,3 +33,5 @@ $node->issues_sql_like(
 	[ 'vacuumdb', '-Z', 'postgres' ],
 	qr/statement: ANALYZE;/,
 	'vacuumdb -Z');
+$node->command_ok([qw(vacuumdb -Z --table=pg_am dbname=template1)],
+				  'vacuumdb with connection string');
diff --git a/src/bin/scripts/t/200_connstr.pl b/src/bin/scripts/t/200_connstr.pl
new file mode 100644
index 0000000000000000000000000000000000000000..89945712d29ac4089fb66b3ae570cced3bef0ced
--- /dev/null
+++ b/src/bin/scripts/t/200_connstr.pl
@@ -0,0 +1,38 @@
+use strict;
+use warnings;
+
+use PostgresNode;
+use TestLib;
+use Test::More tests => 3;
+
+# Tests to check connection string handling in utilities
+
+# In a SQL_ASCII database, pgwin32_message_to_UTF16() needs to
+# interpret everything as UTF8.  We're going to use byte sequences
+# that aren't valid UTF-8 strings, so that would fail.  Use LATIN1,
+# which accepts any byte and has a conversion from each byte to UTF-8.
+$ENV{LC_ALL} = 'C';
+$ENV{PGCLIENTENCODING} = 'LATIN1';
+
+# Create database names covering the range of LATIN1 characters and
+# run the utilities' --all options over them.
+my $dbname1 = generate_ascii_string(1, 63);  # contains '='
+my $dbname2 = generate_ascii_string(67, 129);  # skip 64-66 to keep length to 62
+my $dbname3 = generate_ascii_string(130, 192);
+my $dbname4 = generate_ascii_string(193, 255);
+
+my $node = get_new_node('main');
+$node->init(extra => ['--locale=C', '--encoding=LATIN1']);
+$node->start;
+
+foreach my $dbname ($dbname1, $dbname2, $dbname3, $dbname4, 'CamelCase')
+{
+	$node->run_log(['createdb', $dbname]);
+}
+
+$node->command_ok([qw(vacuumdb --all --echo --analyze-only)],
+				  'vacuumdb --all with unusual database names');
+$node->command_ok([qw(reindexdb --all --echo)],
+				  'reindexdb --all with unusual database names');
+$node->command_ok([qw(clusterdb --all --echo --verbose)],
+				  'clusterdb --all with unusual database names');
diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm
index fede1e601b96d122a3594e01195c6744ed4f51ef..afbdb6332bd8a1a949f2c906f4efeb6aebb849bc 100644
--- a/src/test/perl/PostgresNode.pm
+++ b/src/test/perl/PostgresNode.pm
@@ -243,7 +243,13 @@ sub connstr
 	{
 		return "port=$pgport host=$pghost";
 	}
-	return "port=$pgport host=$pghost dbname=$dbname";
+
+	# Escape properly the database string before using it, only
+	# single quotes and backslashes need to be treated this way.
+	$dbname =~ s#\\#\\\\#g;
+	$dbname =~ s#\'#\\\'#g;
+
+	return "port=$pgport host=$pghost dbname='$dbname'";
 }
 
 =pod
@@ -396,7 +402,8 @@ sub init
 	mkdir $self->backup_dir;
 	mkdir $self->archive_dir;
 
-	TestLib::system_or_bail('initdb', '-D', $pgdata, '-A', 'trust', '-N');
+	TestLib::system_or_bail('initdb', '-D', $pgdata, '-A', 'trust', '-N',
+		@{ $params{extra} });
 	TestLib::system_or_bail($ENV{PG_REGRESS}, '--config-auth', $pgdata);
 
 	open my $conf, ">>$pgdata/postgresql.conf";
@@ -1300,6 +1307,24 @@ sub issues_sql_like
 
 =pod
 
+=item $node->run_log(...)
+
+Runs a shell command like TestLib::run_log, but with PGPORT set so
+that the command will default to connecting to this PostgresNode.
+
+=cut
+
+sub run_log
+{
+	my $self = shift;
+
+	local $ENV{PGPORT} = $self->port;
+
+	TestLib::run_log(@_);
+}
+
+=pod
+
 =back
 
 =cut
diff --git a/src/test/perl/TestLib.pm b/src/test/perl/TestLib.pm
index 51b533e08cd51fe30eb3454af8cf97554ef71695..31e7acd4daea8db486fc0b4d27c6a1821b96f88e 100644
--- a/src/test/perl/TestLib.pm
+++ b/src/test/perl/TestLib.pm
@@ -20,6 +20,7 @@ use SimpleTee;
 use Test::More;
 
 our @EXPORT = qw(
+  generate_ascii_string
   slurp_dir
   slurp_file
   append_to_file
@@ -166,6 +167,19 @@ sub run_log
 	return IPC::Run::run(@_);
 }
 
+# Generate a string made of the given range of ASCII characters
+sub generate_ascii_string
+{
+	my ($from_char, $to_char) = @_;
+	my $res;
+
+	for my $i ($from_char .. $to_char)
+	{
+		$res .= sprintf("%c", $i);
+	}
+	return $res;
+}
+
 sub slurp_dir
 {
 	my ($dir) = @_;
diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
index 14c87c91abdb37b8a68de7621a8bde035dd5a732..1154d4c300e292536c319c53c314c8c978d61749 100644
--- a/src/test/regress/pg_regress.c
+++ b/src/test/regress/pg_regress.c
@@ -876,6 +876,29 @@ initialize_environment(void)
 	load_resultmap();
 }
 
+pg_attribute_unused()
+static const char *
+fmtHba(const char *raw)
+{
+	static char *ret;
+	const char *rp;
+	char	   *wp;
+
+	wp = ret = realloc(ret, 3 + strlen(raw) * 2);
+
+	*wp++ = '"';
+	for (rp = raw; *rp; rp++)
+	{
+		if (*rp == '"')
+			*wp++ = '"';
+		*wp++ = *rp;
+	}
+	*wp++ = '"';
+	*wp++ = '\0';
+
+	return ret;
+}
+
 #ifdef ENABLE_SSPI
 /*
  * Get account and domain/realm names for the current user.  This is based on
@@ -1037,11 +1060,11 @@ config_sspi_auth(const char *pgdata)
 	 * '#'.  Windows forbids the double-quote character itself, so don't
 	 * bother escaping embedded double-quote characters.
 	 */
-	CW(fprintf(ident, "regress  \"%s@%s\"  \"%s\"\n",
-			   accountname, domainname, username) >= 0);
+	CW(fprintf(ident, "regress  \"%s@%s\"  %s\n",
+			   accountname, domainname, fmtHba(username)) >= 0);
 	for (sl = extraroles; sl; sl = sl->next)
-		CW(fprintf(ident, "regress  \"%s@%s\"  \"%s\"\n",
-				   accountname, domainname, sl->str) >= 0);
+		CW(fprintf(ident, "regress  \"%s@%s\"  %s\n",
+				   accountname, domainname, fmtHba(sl->str)) >= 0);
 	CW(fclose(ident) == 0);
 }
 #endif
@@ -2064,7 +2087,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 				 * before we add the specified one.
 				 */
 				free_stringlist(&dblist);
-				split_to_stringlist(optarg, ", ", &dblist);
+				split_to_stringlist(optarg, ",", &dblist);
 				break;
 			case 2:
 				debug = true;
@@ -2114,7 +2137,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 				dlpath = pg_strdup(optarg);
 				break;
 			case 18:
-				split_to_stringlist(optarg, ", ", &extraroles);
+				split_to_stringlist(optarg, ",", &extraroles);
 				break;
 			case 19:
 				add_stringlist_item(&temp_configs, optarg);