diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
new file mode 100644
index e412d71..1aea485
*** a/src/bin/pg_ctl/pg_ctl.c
--- b/src/bin/pg_ctl/pg_ctl.c
*************** static void do_promote(void);
*** 134,139 ****
--- 134,140 ----
  static void do_kill(pgpid_t pid);
  static void print_msg(const char *msg);
  static void adjust_data_dir(void);
+ static char *strip_datadirs(char *orig_post_opts);
  
  #if defined(WIN32) || defined(__CYGWIN__)
  static bool pgwin32_IsInstalled(SC_HANDLE);
*************** read_post_opts(void)
*** 719,724 ****
--- 720,726 ----
  				int			len;
  				char	   *optline;
  				char	   *arg1;
+ 				char	   *orig_post_opts = NULL;
  
  				optline = optlines[0];
  				/* trim off line endings */
*************** read_post_opts(void)
*** 733,742 ****
  				{
  					*arg1 = '\0';		/* terminate so we get only program
  										 * name */
! 					post_opts = arg1 + 1;		/* point past whitespace */
  				}
  				if (exec_path == NULL)
  					exec_path = optline;
  			}
  		}
  	}
--- 735,748 ----
  				{
  					*arg1 = '\0';		/* terminate so we get only program
  										 * name */
! 					orig_post_opts = arg1 + 1;		/* point past whitespace */
  				}
  				if (exec_path == NULL)
  					exec_path = optline;
+ 
+ 				if (orig_post_opts) {
+ 					post_opts = strip_datadirs(orig_post_opts);
+ 				}
  			}
  		}
  	}
*************** do_start(void)
*** 819,826 ****
  
  	read_post_opts();
  
! 	/* No -D or -D already added during server start */
! 	if (ctl_command == RESTART_COMMAND || pgdata_opt == NULL)
  		pgdata_opt = "";
  
  	if (exec_path == NULL)
--- 825,831 ----
  
  	read_post_opts();
  
! 	if (pgdata_opt == NULL)
  		pgdata_opt = "";
  
  	if (exec_path == NULL)
*************** adjust_data_dir(void)
*** 1994,1999 ****
--- 1999,2065 ----
  }
  
  
+ /*
+  * Remove any "-D" "/path/to/datadir" specifications. We don't want to
+  * preserve these during a restart, since the user will be providing
+  * a possibly-conflicting datadir which should take precedence over
+  * the old value(s). Get rid of all such datadir specifications in
+  * the string, since a user might have manually launched the postmaster
+  * with redundant specifications, e.g.
+  *  postgres -D /some/dir/ -D /some/dir/ ...
+  *
+  * Note, the simple parsing here won't cope with path specifications
+  * containing embedded quotes, such as
+  *  "-D" "/foo \" bar/"
+  * but such paths seem to be currently unsupported for other reasons
+  * anyway, since `pg_ctl start` / `pg_ctl stop` have inconsistent
+  * handling of such paths.
+  */
+ static char *
+ strip_datadirs(char *orig_post_opts)
+ {
+ 	char	   *datadir;
+ 	char	   *trailing_quote;
+ 	char	   *tmp = NULL;
+ 	char	   *post_opts = pg_strdup(orig_post_opts);
+ 
+ #define DATADIR_SPEC	"\"-D\" \""
+ 
+ 	datadir = strstr(post_opts, DATADIR_SPEC);
+ 
+ 	while (datadir != NULL) {
+ 		trailing_quote = strchr(datadir + sizeof(DATADIR_SPEC), '"');
+ 		if (trailing_quote) {
+ 			*datadir = '\0';
+ 
+ 			/*
+ 			 * If there are any options after the -D ...
+ 			 * specification, preserve them by concatenating.
+ 			 * post_opts must have enough space for strcat(),
+ 			 * since it is the same size as post_opts, but with
+ 			 * an '\0' inserted at *datadir.
+ 			 */
+ 			if (*(trailing_quote + 1) != '\0') {
+ 				tmp = pg_strdup(trailing_quote + 1);
+ 				strcat(post_opts, tmp);
+ 			}
+ 
+ 			datadir = strstr(post_opts, DATADIR_SPEC);
+ 		}
+ 		else {
+ 			write_stderr(_("%s: unable to parse post_opts: %s"),
+ 						 progname, orig_post_opts);
+ 			post_opts = orig_post_opts;
+ 			break;
+ 		}
+ 	}
+ 
+ 	free(tmp);
+ 	return post_opts;
+ }
+ 
+ 
+ 
  int
  main(int argc, char **argv)
  {
