diff --git a/contrib/pg_upgrade/option.c b/contrib/pg_upgrade/option.c
index bdb7ddb85900bf7aa047bd38b9ddc76c062e490a..3ab1b5cc704ca8da3b1bb77003c9f7f6d485deb3 100644
--- a/contrib/pg_upgrade/option.c
+++ b/contrib/pg_upgrade/option.c
@@ -112,10 +112,12 @@ parseCommandLine(int argc, char *argv[])
 
 			case 'd':
 				old_cluster.pgdata = pg_strdup(optarg);
+				old_cluster.pgconfig = pg_strdup(optarg);
 				break;
 
 			case 'D':
 				new_cluster.pgdata = pg_strdup(optarg);
+				new_cluster.pgconfig = pg_strdup(optarg);
 				break;
 
 			case 'g':
@@ -319,3 +321,61 @@ check_required_directory(char **dirpath, char *envVarName,
 #endif
 		(*dirpath)[strlen(*dirpath) - 1] = 0;
 }
+
+/*
+ * adjust_data_dir
+ *
+ * If a configuration-only directory was specified, find the real data dir
+ * by quering the running server.  This has limited checking because we
+ * can't check for a running server because we can't find postmaster.pid.
+ */
+void
+adjust_data_dir(ClusterInfo *cluster)
+{
+	char		filename[MAXPGPATH];
+	char		cmd[MAXPGPATH], cmd_output[MAX_STRING];
+	FILE	   *fd, *output;
+
+	/* If there is no postgresql.conf, it can't be a config-only dir */
+	snprintf(filename, sizeof(filename), "%s/postgresql.conf", cluster->pgconfig);
+	if ((fd = fopen(filename, "r")) == NULL)
+		return;
+	fclose(fd);
+
+	/* If PG_VERSION exists, it can't be a config-only dir */
+	snprintf(filename, sizeof(filename), "%s/PG_VERSION", cluster->pgconfig);
+	if ((fd = fopen(filename, "r")) != NULL)
+	{
+		fclose(fd);
+		return;
+	}
+
+	/* Must be a configuration directory, so find the real data directory. */
+
+	prep_status("Finding the real data directory for the %s cluster",
+				CLUSTER_NAME(cluster));
+
+	/*
+	 * We don't have a data directory yet, so we can't check the PG
+	 * version, so this might fail --- only works for PG 9.2+.   If this
+	 * fails, pg_upgrade will fail anyway because the data files will not
+	 * be found.
+	 */
+	snprintf(cmd, sizeof(cmd), "\"%s/postmaster\" -D \"%s\" -C data_directory",
+			 cluster->bindir, cluster->pgconfig);
+
+	if ((output = popen(cmd, "r")) == NULL ||
+		fgets(cmd_output, sizeof(cmd_output), output) == NULL)
+		pg_log(PG_FATAL, "Could not get data directory using %s: %s\n",
+		cmd, getErrorText(errno));
+
+	pclose(output);
+
+	/* Remove trailing newline */
+	if (strchr(cmd_output, '\n') != NULL)
+		*strchr(cmd_output, '\n') = '\0';
+
+	cluster->pgdata = pg_strdup(cmd_output);
+
+	check_ok();
+}
diff --git a/contrib/pg_upgrade/pg_upgrade.c b/contrib/pg_upgrade/pg_upgrade.c
index 0568acafb25ded881a0bf52e90bc2756b7f115f8..273561eb8ae49b0148c8bae42f980500599c80e3 100644
--- a/contrib/pg_upgrade/pg_upgrade.c
+++ b/contrib/pg_upgrade/pg_upgrade.c
@@ -68,6 +68,9 @@ main(int argc, char **argv)
 
 	parseCommandLine(argc, argv);
 
+	adjust_data_dir(&old_cluster);
+	adjust_data_dir(&new_cluster);
+
 	output_check_banner(&live_check);
 
 	setup(argv[0], live_check);
diff --git a/contrib/pg_upgrade/pg_upgrade.h b/contrib/pg_upgrade/pg_upgrade.h
index 46aed74450d8f7f59fbab42b0e1ef484d090fdac..0fb16ed7646f16335d7cc3faad88487e166d615a 100644
--- a/contrib/pg_upgrade/pg_upgrade.h
+++ b/contrib/pg_upgrade/pg_upgrade.h
@@ -187,6 +187,7 @@ typedef struct
 	ControlData controldata;	/* pg_control information */
 	DbInfoArr	dbarr;			/* dbinfos array */
 	char	   *pgdata;			/* pathname for cluster's $PGDATA directory */
+	char	   *pgconfig;		/* pathname for cluster's config file directory */
 	char	   *bindir;			/* pathname for cluster's executable directory */
 	unsigned short port;		/* port number where postmaster is waiting */
 	uint32		major_version;	/* PG_VERSION of cluster */
@@ -361,6 +362,7 @@ void print_maps(FileNameMap *maps, int n,
 /* option.c */
 
 void		parseCommandLine(int argc, char *argv[]);
+void		adjust_data_dir(ClusterInfo *cluster);
 
 /* relfilenode.c */
 
diff --git a/contrib/pg_upgrade/server.c b/contrib/pg_upgrade/server.c
index 8c4aec9918440e0a431528e221ef3ca63a3bb5c6..d512ef3d4fe977e8950dc5a3779ec3d4bea33d2b 100644
--- a/contrib/pg_upgrade/server.c
+++ b/contrib/pg_upgrade/server.c
@@ -169,7 +169,7 @@ start_postmaster(ClusterInfo *cluster)
 	snprintf(cmd, sizeof(cmd),
 			 SYSTEMQUOTE "\"%s/pg_ctl\" -w -l \"%s\" -D \"%s\" "
 			 "-o \"-p %d %s\" start >> \"%s\" 2>&1" SYSTEMQUOTE,
-			 cluster->bindir, log_opts.filename2, cluster->pgdata, cluster->port,
+			 cluster->bindir, log_opts.filename2, cluster->pgconfig, cluster->port,
 			 (cluster->controldata.cat_ver >=
 			  BINARY_UPGRADE_SERVER_FLAG_CAT_VER) ? "-b" :
 			 "-c autovacuum=off -c autovacuum_freeze_max_age=2000000000",
@@ -208,17 +208,17 @@ stop_postmaster(bool fast)
 {
 	char		cmd[MAXPGPATH];
 	const char *bindir;
-	const char *datadir;
+	const char *configdir;
 
 	if (os_info.running_cluster == &old_cluster)
 	{
 		bindir = old_cluster.bindir;
-		datadir = old_cluster.pgdata;
+		configdir = old_cluster.pgconfig;
 	}
 	else if (os_info.running_cluster == &new_cluster)
 	{
 		bindir = new_cluster.bindir;
-		datadir = new_cluster.pgdata;
+		configdir = new_cluster.pgconfig;
 	}
 	else
 		return;					/* no cluster running */
@@ -226,7 +226,7 @@ stop_postmaster(bool fast)
 	snprintf(cmd, sizeof(cmd),
 			 SYSTEMQUOTE "\"%s/pg_ctl\" -w -l \"%s\" -D \"%s\" %s stop >> "
 			 "\"%s\" 2>&1" SYSTEMQUOTE,
-			 bindir, log_opts.filename2, datadir, fast ? "-m fast" : "",
+			 bindir, log_opts.filename2, configdir, fast ? "-m fast" : "",
 			 log_opts.filename2);
 
 	exec_prog(fast ? false : true, "%s", cmd);