diff --git a/doc/src/sgml/recovery-config.sgml b/doc/src/sgml/recovery-config.sgml
index 8c24ae2..3071879 100644
--- a/doc/src/sgml/recovery-config.sgml
+++ b/doc/src/sgml/recovery-config.sgml
@@ -11,30 +11,90 @@
 
    <para>
     This chapter describes the settings available in the
-    <filename>recovery.conf</><indexterm><primary>recovery.conf</></>
-    file. They apply only for the duration of the
+    <filename>postgresql.conf</><indexterm><primary>postgresql.conf</></>
+    file that apply only for the duration of the
     recovery.  They must be reset for any subsequent recovery you wish to
-    perform.  They cannot be changed once recovery has begun.
+    perform.
    </para>
 
    <para>
-     Settings in <filename>recovery.conf</> are specified in the format
-     <literal>name = 'value'</>. One parameter is specified per line.
-     Hash marks (<literal>#</literal>) designate the rest of the
-     line as a comment.  To embed a single quote in a parameter
-     value, write two quotes (<literal>''</>).
+    The database server can also be started "in recovery" a term that covers
+    using the server as a standby or for executing a targeted recovery. Typically
+    standby mode would be used to provide high availability and/or read
+    scalability, whereas a targeted recovery is used to recover from data loss.
    </para>
 
    <para>
-    A sample file, <filename>share/recovery.conf.sample</>,
-    is provided in the installation's <filename>share/</> directory.
+    To start the server in standby mode create a zero-length file
+    called <filename>standby.signal</><indexterm><primary>standby.signal</></>
+    in the <varname>signal_file_directory</>. The server will enter recovery and
+    will not stop recovery when the end of archived WAL is reached, but
+    will keep trying to continue recovery by connecting to the sending server as
+    specified by the <varname>sender_conninfo</> setting and/or by
+    fetching new WAL segments using <varname>restore_command</>
+    In this mode you may use parameters
+    in both <xref linkend="archive-recovery-settings"> and
+    <xref linkend="standby-settings"> sections. Parameters from
+    <xref linkend="recovery-target-settings"> will not be used.
    </para>
 
+   <para>
+    To start the server in targeted recovery create a zero-length file called
+    <filename>recovery.signal</><indexterm><primary>recovery.signal</></>
+    in the <varname>signal_file_directory</>.
+    If both <filename>standby.signal</> and <filename>recovery.signal</> files are
+    created, standby mode takes precedence. Targeted recovery mode will end when
+    end of archived WAL is reached, or when <varname>recovery_target</> is reached.
+    In this mode you may use parameters from both
+    <xref linkend="archive-recovery-settings"> and
+    <xref linkend="recovery-target-settings"> sections. Parameters from
+    <xref linkend="standby-settings"> will not be used.
+   </para>
+
+  <sect1 id="recovery-signal-settings">
+
+    <title>Recovery Signal Settings</title>
+     <variablelist>
+
+       <varlistentry id="signal_file_directory" xreflabel="signal_file_directory">
+        <term><varname>signal_file_directory</varname> (<type>string</type>)
+        <indexterm>
+          <primary><varname>signal_file_directory</> recovery parameter</primary>
+          <primary><varname>trigger_file</> a now-deprecated recovery parameter used to specify name of a promotion signal file</primary>
+        </indexterm>
+        </term>
+        <listitem>
+         <para>
+          Specifies a directory where files can be created to signal state changes
+          to the server, also sometimes described as a trigger file though that term
+          is not normally used. The default setting is <varname>data_directory</>.
+         </para>
+         <para>
+          The server will look for <filename>standby.signal</>, <filename>recovery.signal</>
+          and <filename>promote.signal</> files in this directory.
+         </para>
+         <para>
+          The parameter may only be changed at server start.
+         </para>
+        </listitem>
+       </varlistentry>
+
+    </variablelist>
+
+  </sect1>
+
   <sect1 id="archive-recovery-settings">
 
     <title>Archive Recovery Settings</title>
      <variablelist>
 
+     <para>
+      Parameter settings may be changed in <filename>postgresql.conf</filename> or
+      by executing the <command>ALTER SYSTEM</command>. Changes will take some
+      time to take effect, so changes made while not in paused state may not
+      have the desired effect in all cases.
+     </para>
+
      <varlistentry id="restore-command" xreflabel="restore_command">
       <term><varname>restore_command</varname> (<type>string</type>)
       <indexterm>
@@ -45,7 +105,7 @@
        <para>
         The local shell command to execute to retrieve an archived segment of
         the WAL file series. This parameter is required for archive recovery,
-        but optional for streaming replication.
+        but optional for standby mode.
         Any <literal>%f</> in the string is
         replaced by the name of the file to retrieve from the archive,
         and any <literal>%p</> is replaced by the copy destination path name
@@ -154,99 +214,91 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
     <title>Recovery Target Settings</title>
 
      <para>
-      By default, recovery will recover to the end of the WAL log. The
-      following parameters can be used to specify an earlier stopping point.
-      At most one of <varname>recovery_target</>,
-      <varname>recovery_target_lsn</>, <varname>recovery_target_name</>,
-      <varname>recovery_target_time</>, or <varname>recovery_target_xid</>
-      can be used; if more than one of these is specified in the configuration
-      file, the last entry will be used.
+      By default, recovery will recover to the end of the WAL log. An earlier
+      stopping point may be specified using <varname>recovery_target_type</>
+      and in most cases also <varname>recovery_target_value</>, plus the optional
+      parameters <varname>recovery_target_inclusive</>,
+      <varname>recovery_targeti_timeline</> and <varname>recovery_target_action</>.
+     </para>
+
+     <para>
+      Parameter settings may be changed in <filename>postgresql.conf</filename> or
+      by executing the <command>ALTER SYSTEM</command>. Changes will take some
+      time to take effect, so changes made while not in paused state may not
+      have the desired effect in all cases.
      </para>
 
      <variablelist>
-     <varlistentry id="recovery-target" xreflabel="recovery_target">
-      <term><varname>recovery_target</varname><literal> = 'immediate'</literal>
+     <varlistentry id="recovery-target-type" xreflabel="recovery_target_type">
+      <term><varname>recovery_target_type</varname> (<type>enum</type>)
       <indexterm>
-        <primary><varname>recovery_target</> recovery parameter</primary>
+        <primary><varname>recovery_target_type</> targeted recovery parameter</primary>
       </indexterm>
       </term>
       <listitem>
        <para>
-        This parameter specifies that recovery should end as soon as a
-        consistent state is reached, i.e. as early as possible. When restoring
-        from an online backup, this means the point where taking the backup
-        ended.
+        <varname>recovery_target_type</varname> specifies the search criteria used for a
+        a targeted recovery. The default value is <literal>none</literal>. Valid
+        values are <literal>none</literal>, <literal>immediate</literal>,
+        <literal>name</literal>, <literal>timestamp</literal>,
+        <literal>xid</literal> and <literal>lsn</literal>.
        </para>
+
        <para>
-        Technically, this is a string parameter, but <literal>'immediate'</>
-        is currently the only allowed value.
+        Target-type <literal>none</literal> specifies that recovery will not stop
+        until it runs out of WAL, which is the default setting. When not in targeted
+        recovery this is the only meaningful setting.
        </para>
-      </listitem>
-     </varlistentry>
 
-     <varlistentry id="recovery-target-name" xreflabel="recovery_target_name">
-      <term><varname>recovery_target_name</varname> (<type>string</type>)
-      <indexterm>
-        <primary><varname>recovery_target_name</> recovery parameter</primary>
-      </indexterm>
-      </term>
-      <listitem>
        <para>
-        This parameter specifies the named restore point (created with
-        <function>pg_create_restore_point()</>) to which recovery will proceed.
+        Target-type <literal>immediate</literal> specifies that recovery should end as
+        soon as a consistent state is reached, i.e. as early as possible. When restoring
+        from an online backup, this means the point where taking the backup ended.
+        For this target-type, no additional target-specifiers influence the stopping
+        point.
        </para>
-      </listitem>
-     </varlistentry>
 
-     <varlistentry id="recovery-target-time" xreflabel="recovery_target_time">
-      <term><varname>recovery_target_time</varname> (<type>timestamp</type>)
-      <indexterm>
-        <primary><varname>recovery_target_time</> recovery parameter</primary>
-      </indexterm>
-      </term>
-      <listitem>
        <para>
-        This parameter specifies the time stamp up to which recovery
-        will proceed.
+        Target-type <literal>name</literal> specifies that recovery will
+        proceed to the point specified by <varname>recovery_target_value</varname>
+        when interpreted as the name of a restore point created with
+        <function>pg_create_restore_point()</>.
         The precise stopping point is also influenced by
-        <xref linkend="recovery-target-inclusive">.
+        <xref linkend="recovery-target-inclusive"> and
+        <xref linkend="recovery-target-timeline">.
        </para>
-      </listitem>
-     </varlistentry>
 
-     <varlistentry id="recovery-target-xid" xreflabel="recovery_target_xid">
-      <term><varname>recovery_target_xid</varname> (<type>string</type>)
-      <indexterm>
-        <primary><varname>recovery_target_xid</> recovery parameter</primary>
-      </indexterm>
-      </term>
-      <listitem>
        <para>
-        This parameter specifies the transaction ID up to which recovery
-        will proceed. Keep in mind
+        Target-type <literal>timestamp</literal> specifies that recovery will
+        proceed to the point specified by <varname>recovery_target_value</varname>
+        when interpreted as the timestamp of a transaction commit or abort.
+        The precise stopping point is also influenced by
+        <xref linkend="recovery-target-inclusive"> and
+        <xref linkend="recovery-target-timeline">.
+       </para>
+
+       <para>
+        Target-type <literal>xid</literal> specifies that recovery will
+        proceed to the point specified by <varname>recovery_target_value</varname>
+        when interpreted as the transaction ID of a transaction commit or abort.
+        Keep in mind
         that while transaction IDs are assigned sequentially at transaction
         start, transactions can complete in a different numeric order.
         The transactions that will be recovered are those that committed
         before (and optionally including) the specified one.
         The precise stopping point is also influenced by
-        <xref linkend="recovery-target-inclusive">.
+        <xref linkend="recovery-target-inclusive"> and
+        <xref linkend="recovery-target-timeline">.
        </para>
-      </listitem>
-     </varlistentry>
 
-     <varlistentry id="recovery-target-lsn" xreflabel="recovery_target_lsn">
-      <term><varname>recovery_target_lsn</varname> (<type>pg_lsn</type>)
-      <indexterm>
-        <primary><varname>recovery_target_lsn</> recovery parameter</primary>
-      </indexterm>
-      </term>
-      <listitem>
        <para>
-        This parameter specifies the LSN of the transaction log location up
-        to which recovery will proceed. The precise stopping point is also
-        influenced by <xref linkend="recovery-target-inclusive">. This
-        parameter is parsed using the system data type
-        <link linkend="datatype-pg-lsn"><type>pg_lsn</></link>.
+        Target-type <literal>lsn</literal> specifies that recovery will
+        proceed to the point specified by <varname>recovery_target_value</varname>
+        when interpreted as the LSN of any WAL record, parsed using the system
+        data type <link linkend="datatype-pg-lsn"><type>pg_lsn</></link>.
+        The precise stopping point is also influenced by
+        <xref linkend="recovery-target-inclusive"> and
+        <xref linkend="recovery-target-timeline">.
        </para>
       </listitem>
      </varlistentry>
@@ -258,6 +310,23 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
      </para>
 
      <variablelist>
+     <varlistentry id="recovery-target-value"
+                   xreflabel="recovery_target_value">
+      <term><varname>recovery_target_value</varname> (<type>string</type>)
+      <indexterm>
+        <primary><varname>recovery_target_value</> targeted recovery search parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Specifies the stopping point for targeted recovery. The string value
+        is interpreted according to strict rules according to the value of
+        <varname>recovery_target_type</varname>. An empty string may be an
+        invalid value in some cases.
+       </para>
+      </listitem>
+     <variablelist>
+
      <varlistentry id="recovery-target-inclusive"
                    xreflabel="recovery_target_inclusive">
       <term><varname>recovery_target_inclusive</varname> (<type>boolean</type>)
@@ -357,34 +426,21 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
     <title>Standby Server Settings</title>
      <variablelist>
 
-       <varlistentry id="standby-mode" xreflabel="standby_mode">
-        <term><varname>standby_mode</varname> (<type>boolean</type>)
-        <indexterm>
-          <primary><varname>standby_mode</> recovery parameter</primary>
-        </indexterm>
-        </term>
-        <listitem>
-         <para>
-          Specifies whether to start the <productname>PostgreSQL</> server as
-          a standby. If this parameter is <literal>on</>, the server will
-          not stop recovery when the end of archived WAL is reached, but
-          will keep trying to continue recovery by fetching new WAL segments
-          using <varname>restore_command</>
-          and/or by connecting to the primary server as specified by the
-          <varname>primary_conninfo</> setting.
-         </para>
-        </listitem>
-       </varlistentry>
-       <varlistentry id="primary-conninfo" xreflabel="primary_conninfo">
-        <term><varname>primary_conninfo</varname> (<type>string</type>)
+     <para>
+      Parameter settings may be changed only at server start, though later
+      patches may add this capability.
+     </para>
+
+       <varlistentry id="sender-conninfo" xreflabel="sender_conninfo">
+        <term><varname>sender_conninfo</varname> (<type>string</type>)
         <indexterm>
-          <primary><varname>primary_conninfo</> recovery parameter</primary>
+          <primary><varname>sender_conninfo</> recovery parameter</primary>
         </indexterm>
         </term>
         <listitem>
          <para>
           Specifies a connection string to be used for the standby server
-          to connect with the primary. This string is in the format
+          to connect with a sending server. This string is in the format
           described in <xref linkend="libpq-connstring">. If any option is
           unspecified in this string, then the corresponding environment
           variable (see <xref linkend="libpq-envars">) is checked. If the
@@ -393,56 +449,42 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
          </para>
          <para>
           The connection string should specify the host name (or address)
-          of the primary server, as well as the port number if it is not
+          of the sending server, as well as the port number if it is not
           the same as the standby server's default.
           Also specify a user name corresponding to a suitably-privileged role
-          on the primary (see
+          on the sending server (see
           <xref linkend="streaming-replication-authentication">).
-          A password needs to be provided too, if the primary demands password
+          A password needs to be provided too, if the sender demands password
           authentication.  It can be provided in the
-          <varname>primary_conninfo</varname> string, or in a separate
+          <varname>sender_conninfo</varname> string, or in a separate
           <filename>~/.pgpass</> file on the standby server (use
           <literal>replication</> as the database name).
           Do not specify a database name in the
-          <varname>primary_conninfo</varname> string.
+          <varname>sender_conninfo</varname> string.
          </para>
          <para>
           This setting has no effect if <varname>standby_mode</> is <literal>off</>.
          </para>
         </listitem>
        </varlistentry>
-       <varlistentry id="primary-slot-name" xreflabel="primary_slot_name">
-        <term><varname>primary_slot_name</varname> (<type>string</type>)
+
+       <varlistentry id="sender-slot-name" xreflabel="sender_slot_name">
+        <term><varname>sender_slot_name</varname> (<type>string</type>)
         <indexterm>
-          <primary><varname>primary_slot_name</> recovery parameter</primary>
+          <primary><varname>sender_slot_name</> recovery parameter</primary>
         </indexterm>
         </term>
         <listitem>
          <para>
           Optionally specifies an existing replication slot to be used when
-          connecting to the primary via streaming replication to control
+          connecting to the sending server via streaming replication to control
           resource removal on the upstream node
           (see <xref linkend="streaming-replication-slots">).
-          This setting has no effect if <varname>primary_conninfo</> is not
+          This setting has no effect if <varname>sender_conninfo</> is not
           set.
          </para>
         </listitem>
        </varlistentry>
-       <varlistentry id="trigger-file" xreflabel="trigger_file">
-        <term><varname>trigger_file</varname> (<type>string</type>)
-        <indexterm>
-          <primary><varname>trigger_file</> recovery parameter</primary>
-        </indexterm>
-        </term>
-        <listitem>
-         <para>
-          Specifies a trigger file whose presence ends recovery in the
-          standby.  Even if this value is not set, you can still promote
-          the standby using <command>pg_ctl promote</>.
-          This setting has no effect if <varname>standby_mode</> is <literal>off</>.
-         </para>
-        </listitem>
-       </varlistentry>
 
      <varlistentry id="recovery-min-apply-delay" xreflabel="recovery_min_apply_delay">
       <term><varname>recovery_min_apply_delay</varname> (<type>integer</type>)
@@ -453,7 +495,7 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
       <listitem>
        <para>
         By default, a standby server restores WAL records from the
-        primary as soon as possible. It may be useful to have a time-delayed
+        sending server as soon as possible. It may be useful to have a time-delayed
         copy of the data, offering opportunities to correct data loss errors.
         This parameter allows you to delay recovery by a fixed period of time,
         measured in milliseconds if no unit is specified.  For example, if
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index f8ffa5c..e4168c2 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -76,11 +76,13 @@
 
 extern uint32 bootstrap_data_checksum_version;
 
-/* File path names (all relative to $PGDATA) */
+/* File path names */
 #define RECOVERY_COMMAND_FILE	"recovery.conf"
 #define RECOVERY_COMMAND_DONE	"recovery.done"
-#define PROMOTE_SIGNAL_FILE		"promote"
-#define FALLBACK_PROMOTE_SIGNAL_FILE "fallback_promote"
+#define PROMOTE_SIGNAL_FILE	"promote.signal"
+#define FALLBACK_PROMOTE_SIGNAL_FILE "fallback_promote.signal"
+#define RECOVERY_SIGNAL_FILE	"recovery.signal"
+#define STANDBY_SIGNAL_FILE	"standby.signal"
 
 
 /* User-settable parameters */
@@ -241,29 +243,35 @@ static int	LocalXLogInsertAllowed = -1;
 */
 bool		ArchiveRecoveryRequested = false;
 bool		InArchiveRecovery = false;
+static bool	standby_signal_file_found = false;
+static bool	recovery_signal_file_found = false;
 
 /* Was the last xlog file restored from archive, or local? */
 static bool restoredFromArchive = false;
 
 /* options taken from recovery.conf for archive recovery */
-char	   *recoveryRestoreCommand = NULL;
-static char *recoveryEndCommand = NULL;
-static char *archiveCleanupCommand = NULL;
-static RecoveryTargetType recoveryTarget = RECOVERY_TARGET_UNSET;
-static bool recoveryTargetInclusive = true;
-static RecoveryTargetAction recoveryTargetAction = RECOVERY_TARGET_ACTION_PAUSE;
-static TransactionId recoveryTargetXid;
-static TimestampTz recoveryTargetTime;
-static char *recoveryTargetName;
-static XLogRecPtr recoveryTargetLSN;
-static int	recovery_min_apply_delay = 0;
-static TimestampTz recoveryDelayUntilTime;
+char *recoveryRestoreCommand = NULL;
+char *recoveryEndCommand = NULL;
+char *archiveCleanupCommand = NULL;
+char *recoveryTargetTypeString;
+RecoveryTargetType recoveryTarget = RECOVERY_TARGET_UNSET;
+char *recoveryTargetValue = NULL;
+bool recoveryTargetInclusive = true;
+RecoveryTargetAction recoveryTargetAction = RECOVERY_TARGET_ACTION_PAUSE;
+TransactionId recoveryTargetXid;
+TimestampTz recoveryTargetTime;
+char *recoveryTargetName;
+XLogRecPtr recoveryTargetLSN;
+int	recovery_min_apply_delay = 0;
+TimestampTz recoveryDelayUntilTime;
 
 /* options taken from recovery.conf for XLOG streaming */
-static bool StandbyModeRequested = false;
-static char *PrimaryConnInfo = NULL;
-static char *PrimarySlotName = NULL;
-static char *TriggerFile = NULL;
+bool StandbyModeRequested = false;
+
+char *signal_file_directory = NULL;
+char PromoteSignalFile[MAXPGPATH];
+char RecoverySignalFile[MAXPGPATH];
+char StandbySignalFile[MAXPGPATH];
 
 /* are we currently in standby mode? */
 bool		StandbyMode = false;
@@ -289,7 +297,11 @@ static bool recoveryStopAfter;
  * the currently-scanned WAL record was generated).  We also need these
  * timeline values:
  *
- * recoveryTargetTLI: the desired timeline that we want to end in.
+ * recoveryTargetTimeLineGoal: what the user requested, if any
+ *
+ * recoveryTargetTLIRequested: numeric value of requested timeline, if constant
+ *
+ * recoveryTargetTLI: the currently understood target timeline; changes
  *
  * recoveryTargetIsLatest: was the requested target timeline 'latest'?
  *
@@ -305,7 +317,10 @@ static bool recoveryStopAfter;
  * file was created.)  During a sequential scan we do not allow this value
  * to decrease.
  */
-static TimeLineID recoveryTargetTLI;
+char *recoveryTargetTLIString = NULL;
+RecoveryTargetTimeLineGoal recoveryTargetTimeLineGoal = RECOVERY_TARGET_TIMELINE_CONTROLFILE;
+TimeLineID recoveryTargetTLIRequested = 0;
+TimeLineID recoveryTargetTLI = 0;
 static bool recoveryTargetIsLatest = false;
 static List *expectedTLEs;
 static TimeLineID curFileTLI;
@@ -801,7 +816,8 @@ static bool holdingAllLocks = false;
 static MemoryContext walDebugCxt = NULL;
 #endif
 
-static void readRecoveryCommandFile(void);
+static void readRecoverySignalFile(void);
+static void logRecoveryParameters(void);
 static void exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog);
 static bool recoveryStopsBefore(XLogReaderState *record);
 static bool recoveryStopsAfter(XLogReaderState *record);
@@ -4963,261 +4979,170 @@ str_time(pg_time_t tnow)
 
 /*
  * See if there is a recovery command file (recovery.conf), and if so
- * read in parameters for archive recovery and XLOG streaming.
+ * throw an ERROR.
  *
- * The file is parsed using the main configuration parser.
+ * See if there are any recovery signal files and if so, set state for
+ * recovery.
  */
 static void
-readRecoveryCommandFile(void)
+readRecoverySignalFile(void)
 {
-	FILE	   *fd;
-	TimeLineID	rtli = 0;
-	bool		rtliGiven = false;
-	ConfigVariable *item,
-			   *head = NULL,
-			   *tail = NULL;
-	bool		recoveryTargetActionSet = false;
+	struct stat stat_buf;
 
+	if (IsBootstrapProcessingMode())
+		return;
 
-	fd = AllocateFile(RECOVERY_COMMAND_FILE, "r");
-	if (fd == NULL)
+	/*
+	 * Set paths for named signal files
+	 */
+	if (signal_file_directory)
 	{
-		if (errno == ENOENT)
-			return;				/* not there, so no archive recovery */
+		snprintf(StandbySignalFile, MAXPGPATH, "%s/%s", signal_file_directory, STANDBY_SIGNAL_FILE);
+		snprintf(RecoverySignalFile, MAXPGPATH, "%s/%s", signal_file_directory, RECOVERY_SIGNAL_FILE);
+		snprintf(PromoteSignalFile, MAXPGPATH, "%s/%s", signal_file_directory, PROMOTE_SIGNAL_FILE);
+	}
+	else
+	{
+		snprintf(StandbySignalFile, MAXPGPATH, "%s", STANDBY_SIGNAL_FILE);
+		snprintf(RecoverySignalFile, MAXPGPATH, "%s", RECOVERY_SIGNAL_FILE);
+		snprintf(PromoteSignalFile, MAXPGPATH, "%s", PROMOTE_SIGNAL_FILE);
+	}
+
+	/*
+	 * Check for old recovery API file: recovery.conf
+	 */
+	if (stat(RECOVERY_COMMAND_FILE, &stat_buf) == 0)
 		ereport(FATAL,
-				(errcode_for_file_access(),
-				 errmsg("could not open recovery command file \"%s\": %m",
+			(errcode_for_file_access(),
+			 errmsg("deprecated API using recovery command file \"%s\"",
 						RECOVERY_COMMAND_FILE)));
+	/*
+	 * Remove unused .done file, if present. Ignore if absent.
+	 */
+	unlink(RECOVERY_COMMAND_DONE);
+
+	/*
+	 * Check for recovery signal files.
+	 *
+	 * If present, standby signal file takes precedence.
+	 * If neither is present then we won't enter archive recovery.
+	 */
+	if (stat(StandbySignalFile, &stat_buf) == 0)
+	{
+		standby_signal_file_found = true;
+		StandbyModeRequested = true;
+		ArchiveRecoveryRequested = true;
+	}
+	else if (stat(RecoverySignalFile, &stat_buf) == 0)
+	{
+		recovery_signal_file_found = true;
+		StandbyModeRequested = false;
+		ArchiveRecoveryRequested = true;
 	}
+	else
+		return;
 
 	/*
-	 * Since we're asking ParseConfigFp() to report errors as FATAL, there's
-	 * no need to check the return value.
+	 * We don't support standby_mode in standalone backends; that requires
+	 * other processes such as the WAL receiver to be alive.
 	 */
-	(void) ParseConfigFp(fd, RECOVERY_COMMAND_FILE, 0, FATAL, &head, &tail);
+	if (StandbyModeRequested && !IsUnderPostmaster)
+		ereport(FATAL,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+			errmsg("standby mode is not supported by single-user servers")));
 
-	FreeFile(fd);
+	logRecoveryParameters();
+	validateRecoveryParameters();
+}
 
-	for (item = head; item; item = item->next)
-	{
-		if (strcmp(item->name, "restore_command") == 0)
-		{
-			recoveryRestoreCommand = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("restore_command = '%s'",
-									 recoveryRestoreCommand)));
-		}
-		else if (strcmp(item->name, "recovery_end_command") == 0)
-		{
-			recoveryEndCommand = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_end_command = '%s'",
-									 recoveryEndCommand)));
-		}
-		else if (strcmp(item->name, "archive_cleanup_command") == 0)
-		{
-			archiveCleanupCommand = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("archive_cleanup_command = '%s'",
-									 archiveCleanupCommand)));
-		}
-		else if (strcmp(item->name, "recovery_target_action") == 0)
-		{
-			if (strcmp(item->value, "pause") == 0)
-				recoveryTargetAction = RECOVERY_TARGET_ACTION_PAUSE;
-			else if (strcmp(item->value, "promote") == 0)
-				recoveryTargetAction = RECOVERY_TARGET_ACTION_PROMOTE;
-			else if (strcmp(item->value, "shutdown") == 0)
-				recoveryTargetAction = RECOVERY_TARGET_ACTION_SHUTDOWN;
-			else
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				errmsg("invalid value for recovery parameter \"%s\": \"%s\"",
-					   "recovery_target_action",
-					   item->value),
-						 errhint("Valid values are \"pause\", \"promote\", and \"shutdown\".")));
+static void
+logRecoveryParameters(void)
+{
+	int	normal_log_level = LOG; //DEBUG2;
 
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_target_action = '%s'",
-									 item->value)));
+	/*
+	 * Log messages for recovery parameters at server start
+	 */
+	ereport(normal_log_level,
+		(errmsg_internal("standby_mode = '%s'", (StandbyModeRequested ? "on " : "off"))));
 
-			recoveryTargetActionSet = true;
-		}
-		else if (strcmp(item->name, "recovery_target_timeline") == 0)
-		{
-			rtliGiven = true;
-			if (strcmp(item->value, "latest") == 0)
-				rtli = 0;
-			else
-			{
-				errno = 0;
-				rtli = (TimeLineID) strtoul(item->value, NULL, 0);
-				if (errno == EINVAL || errno == ERANGE)
-					ereport(FATAL,
-							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-							 errmsg("recovery_target_timeline is not a valid number: \"%s\"",
-									item->value)));
-			}
-			if (rtli)
-				ereport(DEBUG2,
-				   (errmsg_internal("recovery_target_timeline = %u", rtli)));
-			else
-				ereport(DEBUG2,
-					 (errmsg_internal("recovery_target_timeline = latest")));
-		}
-		else if (strcmp(item->name, "recovery_target_xid") == 0)
-		{
-			errno = 0;
-			recoveryTargetXid = (TransactionId) strtoul(item->value, NULL, 0);
-			if (errno == EINVAL || errno == ERANGE)
-				ereport(FATAL,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				  errmsg("recovery_target_xid is not a valid number: \"%s\"",
-						 item->value)));
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_target_xid = %u",
-									 recoveryTargetXid)));
-			recoveryTarget = RECOVERY_TARGET_XID;
-		}
-		else if (strcmp(item->name, "recovery_target_time") == 0)
-		{
-			recoveryTarget = RECOVERY_TARGET_TIME;
+	if (recoveryRestoreCommand != NULL)
+		ereport(normal_log_level,
+			(errmsg_internal("restore_command = '%s'", recoveryRestoreCommand)));
 
-			/*
-			 * Convert the time string given by the user to TimestampTz form.
-			 */
-			recoveryTargetTime =
-				DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
-												CStringGetDatum(item->value),
-												ObjectIdGetDatum(InvalidOid),
-														Int32GetDatum(-1)));
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_target_time = '%s'",
-								   timestamptz_to_str(recoveryTargetTime))));
-		}
-		else if (strcmp(item->name, "recovery_target_name") == 0)
-		{
-			recoveryTarget = RECOVERY_TARGET_NAME;
+	if (recoveryEndCommand != NULL)
+		ereport(normal_log_level,
+			(errmsg_internal("recovery_end_command = '%s'", recoveryRestoreCommand)));
 
-			recoveryTargetName = pstrdup(item->value);
-			if (strlen(recoveryTargetName) >= MAXFNAMELEN)
-				ereport(FATAL,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("recovery_target_name is too long (maximum %d characters)",
-								MAXFNAMELEN - 1)));
+	if (archiveCleanupCommand != NULL)
+		ereport(normal_log_level,
+			(errmsg_internal("archive_cleanup_command = '%s'", archiveCleanupCommand)));
 
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_target_name = '%s'",
-									 recoveryTargetName)));
-		}
-		else if (strcmp(item->name, "recovery_target_lsn") == 0)
-		{
-			recoveryTarget = RECOVERY_TARGET_LSN;
+	if (SenderConnInfo != NULL)
+		ereport(normal_log_level,
+			(errmsg_internal("sender_conninfo = '%s'", SenderConnInfo)));
 
-			/*
-			 * Convert the LSN string given by the user to XLogRecPtr form.
-			 */
-			recoveryTargetLSN =
-				DatumGetLSN(DirectFunctionCall3(pg_lsn_in,
-												CStringGetDatum(item->value),
-												ObjectIdGetDatum(InvalidOid),
-														Int32GetDatum(-1)));
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_target_lsn = '%X/%X'",
-									 (uint32) (recoveryTargetLSN >> 32),
-									 (uint32) recoveryTargetLSN)));
-		}
-		else if (strcmp(item->name, "recovery_target") == 0)
-		{
-			if (strcmp(item->value, "immediate") == 0)
-				recoveryTarget = RECOVERY_TARGET_IMMEDIATE;
-			else
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				errmsg("invalid value for recovery parameter \"%s\": \"%s\"",
-					   "recovery_target",
-					   item->value),
-					   errhint("The only allowed value is \"immediate\".")));
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_target = '%s'",
-									 item->value)));
-		}
-		else if (strcmp(item->name, "recovery_target_inclusive") == 0)
-		{
-			/*
-			 * does nothing if a recovery_target is not also set
-			 */
-			if (!parse_bool(item->value, &recoveryTargetInclusive))
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("parameter \"%s\" requires a Boolean value",
-								"recovery_target_inclusive")));
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_target_inclusive = %s",
-									 item->value)));
-		}
-		else if (strcmp(item->name, "standby_mode") == 0)
-		{
-			if (!parse_bool(item->value, &StandbyModeRequested))
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("parameter \"%s\" requires a Boolean value",
-								"standby_mode")));
-			ereport(DEBUG2,
-					(errmsg_internal("standby_mode = '%s'", item->value)));
-		}
-		else if (strcmp(item->name, "primary_conninfo") == 0)
-		{
-			PrimaryConnInfo = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("primary_conninfo = '%s'",
-									 PrimaryConnInfo)));
-		}
-		else if (strcmp(item->name, "primary_slot_name") == 0)
-		{
-			ReplicationSlotValidateName(item->value, ERROR);
-			PrimarySlotName = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("primary_slot_name = '%s'",
-									 PrimarySlotName)));
-		}
-		else if (strcmp(item->name, "trigger_file") == 0)
+	if (SenderSlotName != NULL)
+		ereport(normal_log_level,
+			(errmsg_internal("sender_slot_name = '%s'", SenderSlotName)));
+
+	if (recovery_min_apply_delay > 0)
+		ereport(normal_log_level,
+			(errmsg_internal("recovery_min_apply_delay = '%u'", recovery_min_apply_delay)));
+
+	/*
+	 * Check details for recovery target, if any
+	 */
+	if (recoveryTarget > RECOVERY_TARGET_UNSET)
+	{
+		ereport(normal_log_level,
+			(errmsg_internal("recovery_target_type = '%s'", RecoveryTargetText(recoveryTarget))));
+		if (recoveryTargetValue != NULL)
+			ereport(normal_log_level,
+				(errmsg_internal("recovery_target_value = '%s'", recoveryTargetValue)));
+		ereport(normal_log_level,
+			(errmsg_internal("recovery_target_inclusive = '%s'", (recoveryTargetInclusive ? "on " : "off"))));
+
+		if (recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_CONTROLFILE)
+			ereport(normal_log_level,
+				(errmsg_internal("recovery_target_timeline = '%u' (from controlfile)",
+					recoveryTargetTLI)));
+		else if (recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_LATEST)
+			ereport(normal_log_level,
+				(errmsg_internal("recovery_target_timeline = 'latest'")));
+		else
 		{
-			TriggerFile = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("trigger_file = '%s'",
-									 TriggerFile)));
+			Assert(recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_NUMERIC);
+			ereport(normal_log_level,
+				(errmsg_internal("recovery_target_timeline = '%u'",
+					recoveryTargetTLIRequested)));
 		}
-		else if (strcmp(item->name, "recovery_min_apply_delay") == 0)
-		{
-			const char *hintmsg;
+	}
 
-			if (!parse_int(item->value, &recovery_min_apply_delay, GUC_UNIT_MS,
-						   &hintmsg))
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("parameter \"%s\" requires a temporal value",
-								"recovery_min_apply_delay"),
-						 hintmsg ? errhint("%s", _(hintmsg)) : 0));
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_min_apply_delay = '%s'", item->value)));
-		}
-		else
+	ereport(normal_log_level,
+		(errmsg_internal("recovery_target_action = '%s'", RecoveryTargetActionText(recoveryTargetAction))));
+}
+
+void
+validateRecoveryParameters(void)
+{
+	if (!ArchiveRecoveryRequested)
+		return;
+
+	if (recoveryTarget > RECOVERY_TARGET_UNSET &&
+		recoveryTargetValue == NULL)
 			ereport(FATAL,
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-					 errmsg("unrecognized recovery parameter \"%s\"",
-							item->name)));
-	}
+					 errmsg("must specify recovery_target_value when recovery_target_type is set")));
 
 	/*
 	 * Check for compulsory parameters
 	 */
 	if (StandbyModeRequested)
 	{
-		if (PrimaryConnInfo == NULL && recoveryRestoreCommand == NULL)
+		if (SenderConnInfo == NULL && recoveryRestoreCommand == NULL)
 			ereport(WARNING,
-					(errmsg("recovery command file \"%s\" specified neither primary_conninfo nor restore_command",
-							RECOVERY_COMMAND_FILE),
+					(errmsg("specified neither primary_conninfo nor restore_command"),
 					 errhint("The database server will regularly poll the pg_wal subdirectory to check for files placed there.")));
 	}
 	else
@@ -5225,8 +5150,7 @@ readRecoveryCommandFile(void)
 		if (recoveryRestoreCommand == NULL)
 			ereport(FATAL,
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-					 errmsg("recovery command file \"%s\" must specify restore_command when standby mode is not enabled",
-							RECOVERY_COMMAND_FILE)));
+					 errmsg("must specify restore_command when standby mode is not enabled")));
 	}
 
 	/*
@@ -5235,50 +5159,46 @@ readRecoveryCommandFile(void)
 	 * hot_standby = off, which was surprising behaviour.
 	 */
 	if (recoveryTargetAction == RECOVERY_TARGET_ACTION_PAUSE &&
-		recoveryTargetActionSet &&
 		!EnableHotStandby)
 		recoveryTargetAction = RECOVERY_TARGET_ACTION_SHUTDOWN;
 
 	/*
-	 * We don't support standby_mode in standalone backends; that requires
-	 * other processes such as the WAL receiver to be alive.
-	 */
-	if (StandbyModeRequested && !IsUnderPostmaster)
-		ereport(FATAL,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-			errmsg("standby mode is not supported by single-user servers")));
-
-	/* Enable fetching from archive recovery area */
-	ArchiveRecoveryRequested = true;
-
-	/*
 	 * If user specified recovery_target_timeline, validate it or compute the
 	 * "latest" value.  We can't do this until after we've gotten the restore
 	 * command and set InArchiveRecovery, because we need to fetch timeline
 	 * history files from the archive.
 	 */
-	if (rtliGiven)
+	if (recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_NUMERIC)
 	{
-		if (rtli)
-		{
-			/* Timeline 1 does not have a history file, all else should */
-			if (rtli != 1 && !existsTimeLineHistory(rtli))
-				ereport(FATAL,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("recovery target timeline %u does not exist",
-								rtli)));
-			recoveryTargetTLI = rtli;
-			recoveryTargetIsLatest = false;
-		}
-		else
-		{
-			/* We start the "latest" search from pg_control's timeline */
-			recoveryTargetTLI = findNewestTimeLine(recoveryTargetTLI);
-			recoveryTargetIsLatest = true;
-		}
-	}
+		TimeLineID rtli = recoveryTargetTLIRequested;
 
-	FreeConfigVariables(head);
+		/* Timeline 1 does not have a history file, all else should */
+		if (rtli != 1 && !existsTimeLineHistory(rtli))
+			ereport(FATAL,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("recovery target timeline %u does not exist",
+							rtli)));
+		recoveryTargetTLI = rtli;
+
+		/*
+		 * The user has requested a specific tli. This might be the latest
+		 * timeline but we don't know that; the point here is that we do not
+		 * allow the recoveryTargetTLI to follow any changes.
+		 */
+		recoveryTargetIsLatest = false;
+	}
+	else if (recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_LATEST)
+	{
+		/* We start the "latest" search from pg_control's timeline */
+		recoveryTargetTLI = findNewestTimeLine(recoveryTargetTLI);
+		recoveryTargetIsLatest = true;
+	}
+	else
+	{
+		/* else we just use the recoveryTargetTLI as already read from ControlFile */
+		Assert(recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_CONTROLFILE);
+		recoveryTargetIsLatest = false;
+	}
 }
 
 /*
@@ -5379,11 +5299,19 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog)
 	unlink(recoveryPath);		/* ignore any error */
 
 	/*
-	 * Rename the config file out of the way, so that we don't accidentally
+	 * Rename the signal files out of the way, so that we don't accidentally
 	 * re-enter archive recovery mode in a subsequent crash.
 	 */
-	unlink(RECOVERY_COMMAND_DONE);
-	durable_rename(RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE, FATAL);
+	if (unlink(StandbySignalFile) != 0 && standby_signal_file_found)
+		ereport(ERROR,
+			(errcode_for_file_access(),
+			 errmsg("could not remove file \"%s\": %m",
+					StandbySignalFile)));
+	if (unlink(RecoverySignalFile) != 0 && recovery_signal_file_found)
+		ereport(ERROR,
+			(errcode_for_file_access(),
+			 errmsg("could not remove file \"%s\": %m",
+					RecoverySignalFile)));
 
 	ereport(LOG,
 			(errmsg("archive recovery complete")));
@@ -6114,10 +6042,9 @@ StartupXLOG(void)
 		recoveryTargetTLI = ControlFile->checkPointCopy.ThisTimeLineID;
 
 	/*
-	 * Check for recovery control file, and if so set up state for offline
-	 * recovery
+	 * Check for signal files, and if so set up state for offline recovery
 	 */
-	readRecoveryCommandFile();
+	readRecoverySignalFile();
 
 	/*
 	 * Save archive_cleanup_command in shared memory so that other processes
@@ -11383,7 +11310,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 					 * that when we later jump backwards to start redo at
 					 * RedoStartLSN, we will have the logs streamed already.
 					 */
-					if (PrimaryConnInfo)
+					if (SenderConnInfo)
 					{
 						XLogRecPtr	ptr;
 						TimeLineID	tli;
@@ -11404,8 +11331,8 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 									 tli, curFileTLI);
 						}
 						curFileTLI = tli;
-						RequestXLogStreaming(tli, ptr, PrimaryConnInfo,
-											 PrimarySlotName);
+						RequestXLogStreaming(tli, ptr, SenderConnInfo,
+										SenderSlotName);
 						receivedUpto = 0;
 					}
 
@@ -11733,14 +11660,15 @@ CheckForStandbyTrigger(void)
 		return true;
 	}
 
-	if (TriggerFile == NULL)
-		return false;
-
-	if (stat(TriggerFile, &stat_buf) == 0)
+	/*
+	 * Check for PromoteSignalFile... this is now a constant filename, with only the
+	 * filepath varying, so a user can still specify what they need.
+	 */
+	if (stat(PromoteSignalFile, &stat_buf) == 0)
 	{
 		ereport(LOG,
-				(errmsg("trigger file found: %s", TriggerFile)));
-		unlink(TriggerFile);
+				(errmsg("promote signal file found: %s", PromoteSignalFile)));
+		unlink(PromoteSignalFile);
 		triggered = true;
 		fast_promote = true;
 		return true;
@@ -11748,8 +11676,8 @@ CheckForStandbyTrigger(void)
 	else if (errno != ENOENT)
 		ereport(ERROR,
 				(errcode_for_file_access(),
-				 errmsg("could not stat trigger file \"%s\": %m",
-						TriggerFile)));
+				 errmsg("could not stat promote signal file \"%s\": %m",
+						PromoteSignalFile)));
 
 	return false;
 }
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index bc7253f..f23e131 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -328,10 +328,11 @@ pg_create_restore_point(PG_FUNCTION_ARGS)
 
 	restore_name_str = text_to_cstring(restore_name);
 
-	if (strlen(restore_name_str) >= MAXFNAMELEN)
+	if (strlen(restore_name_str) >= MAXRESTOREPOINTNAMELEN)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("value too long for restore point (maximum %d characters)", MAXFNAMELEN - 1)));
+				 errmsg("value too long for restore point (maximum %d characters)",
+							MAXRESTOREPOINTNAMELEN - 1)));
 
 	restorepoint = XLogRestorePoint(restore_name_str);
 
diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c
index a7ae7e3..74b72c9 100644
--- a/src/backend/postmaster/startup.c
+++ b/src/backend/postmaster/startup.c
@@ -153,6 +153,7 @@ HandleStartupProcInterrupts(void)
 	{
 		got_SIGHUP = false;
 		ProcessConfigFile(PGC_SIGHUP);
+		validateRecoveryParameters();
 	}
 
 	/*
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index cc3cf7d..01f62b5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -70,9 +70,11 @@
 
 
 /* GUC variables */
-int			wal_receiver_status_interval;
-int			wal_receiver_timeout;
-bool		hot_standby_feedback;
+int wal_receiver_status_interval;
+int wal_receiver_timeout;
+bool hot_standby_feedback;
+char *SenderConnInfo;
+char *SenderSlotName;
 
 /* libpqwalreceiver connection */
 static WalReceiverConn *wrconn = NULL;
@@ -415,9 +417,33 @@ WalReceiverMain(void)
 
 				if (got_SIGHUP)
 				{
+					char	*conninfo = pstrdup(SenderConnInfo);
+					char	*slotname = pstrdup(SenderSlotName);
+
 					got_SIGHUP = false;
 					ProcessConfigFile(PGC_SIGHUP);
 					XLogWalRcvSendHSFeedback(true);
+
+					/*
+					 * If sender_conninfo has been changed while walreceiver is running,
+					 * shut down walreceiver so that a new walreceiver is started and
+					 * initiates replication with the new connection information.
+					 */
+					if (strcmp(conninfo, SenderConnInfo) != 0)
+						ereport(FATAL,
+								(errcode(ERRCODE_ADMIN_SHUTDOWN),
+								 errmsg("closing replication connection because sender_conninfo was changed")));
+
+					/*
+					 * And the same for sender_slot_name.
+					 */
+					if (strcmp(slotname, SenderSlotName) != 0)
+						ereport(FATAL,
+								(errcode(ERRCODE_ADMIN_SHUTDOWN),
+								 errmsg("closing replication connection because sender_slot_name was changed")));
+
+					pfree(conninfo);
+					pfree(slotname);
 				}
 
 				/* See if we can read data immediately */
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 946ba9e..b560e48 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -31,6 +31,7 @@
 #include "access/transam.h"
 #include "access/twophase.h"
 #include "access/xact.h"
+#include "access/xlog.h"
 #include "catalog/namespace.h"
 #include "commands/async.h"
 #include "commands/prepare.h"
@@ -77,6 +78,7 @@
 #include "utils/guc_tables.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
+#include "utils/pg_lsn.h"
 #include "utils/plancache.h"
 #include "utils/portal.h"
 #include "utils/ps_status.h"
@@ -182,6 +184,15 @@ static void assign_application_name(const char *newval, void *extra);
 static bool check_cluster_name(char **newval, void **extra, GucSource source);
 static const char *show_unix_socket_permissions(void);
 static const char *show_log_file_mode(void);
+static bool check_recovery_target_type(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_type(const char *newval, void *extra);
+static bool check_recovery_target_value(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_value(const char *newval, void *extra);
+static bool check_recovery_target_timeline(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_timeline(const char *newval, void *extra);
+static bool check_recovery_target_action(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_action(const char *newval, void *extra);
+static bool check_sender_slot_name(char **newval, void **extra, GucSource source);
 
 /* Private functions in guc-file.l that need to be called from guc.c */
 static ConfigVariable *ProcessConfigFileInternal(GucContext context,
@@ -459,6 +470,9 @@ char	   *IdentFileName;
 char	   *external_pid_file;
 
 char	   *pgstat_temp_directory;
+char	   *signal_file_directory;
+char	*recovery_target_timeline_string;
+char	*recovery_target_action_string;
 
 char	   *application_name;
 
@@ -592,6 +606,10 @@ const char *const config_group_names[] =
 	gettext_noop("Write-Ahead Log / Checkpoints"),
 	/* WAL_ARCHIVING */
 	gettext_noop("Write-Ahead Log / Archiving"),
+	/* WAL_ARCHIVE_RECOVERY */
+	gettext_noop("Write-Ahead Log / Archive Recovery"),
+	/* WAL_RECOVERY_TARGET */
+	gettext_noop("Write-Ahead Log / Recovery Target"),
 	/* REPLICATION */
 	gettext_noop("Replication"),
 	/* REPLICATION_SENDING */
@@ -1549,6 +1567,16 @@ static struct config_bool ConfigureNamesBool[] =
 	},
 
 	{
+		{"recovery_target_inclusive", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets whether to include or exclude transaction with recovery target."),
+			NULL
+		},
+		&recoveryTargetInclusive,
+		true,
+		NULL, NULL, NULL
+	},
+
+	{
 		{"hot_standby", PGC_POSTMASTER, REPLICATION_STANDBY,
 			gettext_noop("Allows connections and queries during recovery."),
 			NULL
@@ -1789,8 +1817,19 @@ static struct config_int ConfigureNamesInt[] =
 	},
 
 	{
+		{"recovery_min_apply_delay", PGC_SIGHUP, REPLICATION_STANDBY,
+			gettext_noop("Sets the minimum delay to apply changes during recovery."),
+			NULL,
+			GUC_UNIT_MS
+		},
+		&recovery_min_apply_delay,
+		0, 0, INT_MAX,
+		NULL, NULL, NULL
+	},
+
+	{
 		{"wal_receiver_status_interval", PGC_SIGHUP, REPLICATION_STANDBY,
-			gettext_noop("Sets the maximum interval between WAL receiver status reports to the primary."),
+			gettext_noop("Sets the maximum interval between WAL receiver status reports to the sending server."),
 			NULL,
 			GUC_UNIT_S
 		},
@@ -1801,7 +1840,7 @@ static struct config_int ConfigureNamesInt[] =
 
 	{
 		{"wal_receiver_timeout", PGC_SIGHUP, REPLICATION_STANDBY,
-			gettext_noop("Sets the maximum wait time to receive data from the primary."),
+			gettext_noop("Sets the maximum wait time to receive data from the sending server."),
 			NULL,
 			GUC_UNIT_MS
 		},
@@ -2996,6 +3035,98 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
+		{"restore_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+			gettext_noop("Sets the shell command that will retrieve an archived WAL file."),
+			NULL
+		},
+		&recoveryRestoreCommand,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"archive_cleanup_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+			gettext_noop("Sets the shell command that will be executed at every restartpoint."),
+			NULL
+		},
+		&archiveCleanupCommand,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"recovery_end_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+			gettext_noop("Sets the shell command that will be executed once only at the end of recovery."),
+			NULL
+		},
+		&recoveryEndCommand,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"recovery_target_type", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the type of desired recovery target."),
+			NULL
+		},
+		&recoveryTargetTypeString,
+		"",
+		check_recovery_target_type, assign_recovery_target_type, NULL
+	},
+
+	{
+		{"recovery_target_value", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the value of the recovery taregt up to which recovery will proceed."),
+			NULL
+		},
+		&recoveryTargetValue,
+		"",
+		check_recovery_target_value, assign_recovery_target_value, NULL
+	},
+
+	{
+		{"recovery_target_timeline", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets recovering into a particular timeline."),
+			NULL
+		},
+		&recovery_target_timeline_string,
+		"",
+		check_recovery_target_timeline, assign_recovery_target_timeline, NULL
+	},
+
+	{
+		{"recovery_target_action", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the action to perform upon reaching the recovery target."),
+			NULL
+		},
+		&recovery_target_action_string,
+		"",
+		check_recovery_target_action, assign_recovery_target_action, NULL
+	},
+
+	{
+		{"sender_conninfo", PGC_SIGHUP, REPLICATION_STANDBY,
+			gettext_noop("Sets the connection string to be used to connect with the sending server."),
+			NULL,
+			GUC_SUPERUSER_ONLY
+		},
+		&SenderConnInfo,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"sender_slot_name", PGC_SIGHUP, REPLICATION_STANDBY,
+			gettext_noop("Sets the name of the replication slot to use on the sending server."),
+			NULL,
+			GUC_SUPERUSER_ONLY
+		},
+		&SenderSlotName,
+		"",
+		check_sender_slot_name, NULL, NULL
+	},
+
+	{
 		{"client_encoding", PGC_USERSET, CLIENT_CONN_LOCALE,
 			gettext_noop("Sets the client's character set encoding."),
 			NULL,
@@ -3475,6 +3606,17 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
+		{"signal_file_directory", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+			gettext_noop("Signal files may be written to the specified directory."),
+			NULL,
+			GUC_SUPERUSER_ONLY
+		},
+		&signal_file_directory,
+		NULL,
+		check_canonical_path, NULL, NULL
+	},
+
+	{
 		{"stats_temp_directory", PGC_SIGHUP, STATS_COLLECTOR,
 			gettext_noop("Writes temporary statistics files to the specified directory."),
 			NULL,
@@ -10335,4 +10477,301 @@ show_log_file_mode(void)
 	return buf;
 }
 
+static bool
+check_recovery_target_type(char **newval, void **extra, GucSource source)
+{
+	RecoveryTargetType *myextra;
+	RecoveryTargetType rt = RECOVERY_TARGET_UNSET;
+
+	if (strcmp(*newval, "xid") == 0)
+		rt = RECOVERY_TARGET_XID;
+	else if (strcmp(*newval, "timestamp") == 0)
+		rt = RECOVERY_TARGET_TIME;
+	else if (strcmp(*newval, "name") == 0)
+		rt = RECOVERY_TARGET_NAME;
+	else if (strcmp(*newval, "lsn") == 0)
+		rt = RECOVERY_TARGET_LSN;
+	else if (strcmp(*newval, "immediate") == 0)
+		rt = RECOVERY_TARGET_IMMEDIATE;
+	else if (strcmp(*newval, "") != 0)
+	{
+		GUC_check_errdetail("recovery_target_type is not valid: \"%s\"", *newval);
+		return false;
+	}
+
+	myextra = (RecoveryTargetType *) guc_malloc(ERROR, sizeof(RecoveryTargetType));
+	*myextra = rt;
+	*extra = (void *) myextra;
+
+	return true;
+}
+
+static void
+assign_recovery_target_type(const char *newval, void *extra)
+{
+	recoveryTarget = *((RecoveryTargetType *) extra);
+}
+
+static bool
+check_recovery_target_value(char **newval, void **extra, GucSource source)
+{
+	bool valid = false;
+
+	/*
+	 * Value must be present in some cases, must not be present in others
+	 */
+	if (strcmp(*newval, "") == 0)
+	{
+		if (recoveryTarget == RECOVERY_TARGET_UNSET ||
+			recoveryTarget == RECOVERY_TARGET_IMMEDIATE)
+			valid = true;
+	}
+	else
+	{
+		if (recoveryTarget == RECOVERY_TARGET_UNSET ||
+			recoveryTarget == RECOVERY_TARGET_IMMEDIATE)
+			valid = false;
+		else
+			valid = true;
+	}
+
+	if (!valid)
+	{
+		GUC_check_errdetail("recovery_target_value is not valid: \"%s\"", *newval);
+		return false;
+	}
+
+	/*
+	 * We assume that recovery_target_type has already been parsed
+	 * since it sorts alphabetically before recovery_target_value.
+	 */
+	switch (recoveryTarget)
+	{
+		case RECOVERY_TARGET_UNSET:
+		case RECOVERY_TARGET_IMMEDIATE:
+			/* No value, so do nothing */
+			break;
+
+		case RECOVERY_TARGET_XID:
+			{
+				TransactionId	xid;
+				TransactionId	*myextra;
+
+				errno = 0;
+				xid = (TransactionId) strtoul(*newval, NULL, 0);
+				if (errno == EINVAL || errno == ERANGE)
+				{
+					GUC_check_errdetail("recovery_target_value is not a valid number: \"%s\"",
+								*newval);
+					return false;
+				}
+
+				myextra = (TransactionId *) guc_malloc(ERROR, sizeof(TransactionId));
+				*myextra = xid;
+				*extra = (void *) myextra;
+			}
+			break;
+
+		case RECOVERY_TARGET_TIME:
+			{
+				TimestampTz     time;
+				TimestampTz     *myextra;
+				MemoryContext oldcontext = CurrentMemoryContext;
+
+				PG_TRY();
+				{
+					time = DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
+												CStringGetDatum(*newval),
+												ObjectIdGetDatum(InvalidOid),
+												Int32GetDatum(-1)));
+				}
+				PG_CATCH();
+				{
+					ErrorData  *edata;
+
+					/* Save error info */
+					MemoryContextSwitchTo(oldcontext);
+					edata = CopyErrorData();
+					FlushErrorState();
+
+					/* Pass the error message */
+					GUC_check_errdetail("%s", edata->message);
+					FreeErrorData(edata);
+					return false;
+				}
+				PG_END_TRY();
+
+				myextra = (TimestampTz *) guc_malloc(ERROR, sizeof(TimestampTz));
+				*myextra = time;
+				*extra = (void *) myextra;
+			}
+			break;
+
+		case RECOVERY_TARGET_NAME:
+			/* Use the value of newval directly */
+			if (strlen(*newval) > MAXRESTOREPOINTNAMELEN)
+			{
+				GUC_check_errdetail("recovery_target_value is too long (maximum %d characters)",
+									MAXRESTOREPOINTNAMELEN);
+				return false;
+			}
+			break;
+
+		case RECOVERY_TARGET_LSN:
+			{
+				XLogRecPtr	lsn;
+				XLogRecPtr	*myextra;
+				MemoryContext oldcontext = CurrentMemoryContext;
+
+				/*
+				 * Convert the LSN string given by the user to XLogRecPtr form.
+				 */
+				PG_TRY();
+				{
+					lsn =
+						DatumGetLSN(DirectFunctionCall3(pg_lsn_in,
+													CStringGetDatum(*newval),
+													ObjectIdGetDatum(InvalidOid),
+													Int32GetDatum(-1)));
+				}
+				PG_CATCH();
+				{
+					ErrorData  *edata;
+
+					/* Save error info */
+					MemoryContextSwitchTo(oldcontext);
+					edata = CopyErrorData();
+					FlushErrorState();
+
+					/* Pass the error message */
+					GUC_check_errdetail("%s", edata->message);
+					FreeErrorData(edata);
+					return false;
+				}
+				PG_END_TRY();
+
+				myextra = (XLogRecPtr *) guc_malloc(ERROR, sizeof(XLogRecPtr));
+				*myextra = lsn;
+				*extra = (void *) myextra;
+			}
+			break;
+	}
+
+	return true;
+}
+
+static void
+assign_recovery_target_value(const char *newval, void *extra)
+{
+	switch (recoveryTarget)
+	{
+		case RECOVERY_TARGET_UNSET:
+		case RECOVERY_TARGET_IMMEDIATE:
+			break;
+
+		case RECOVERY_TARGET_XID:
+			recoveryTargetXid = *((TransactionId *) extra);
+			break;
+
+		case RECOVERY_TARGET_TIME:
+			recoveryTargetTime = *((TimestampTz *) extra);
+			break;
+
+		case RECOVERY_TARGET_NAME:
+			if (newval && *newval)
+				recoveryTargetName = (char *) newval;
+			break;
+
+		case RECOVERY_TARGET_LSN:
+			recoveryTargetLSN = *((XLogRecPtr *) extra);
+			break;
+	}
+}
+
+static bool
+check_recovery_target_timeline(char **newval, void **extra, GucSource source)
+{
+	RecoveryTargetTimeLineGoal rttg = RECOVERY_TARGET_TIMELINE_CONTROLFILE;
+	RecoveryTargetTimeLineGoal *myextra;
+
+	if (strcmp(*newval, "latest") == 0)
+		rttg = RECOVERY_TARGET_TIMELINE_LATEST;
+	else if (strcmp(*newval, "controlfile") == 0 || strcmp(*newval, "") == 0)
+		rttg = RECOVERY_TARGET_TIMELINE_CONTROLFILE;
+	else
+	{
+		TimeLineID tli;
+
+		errno = 0;
+		tli = (TimeLineID) strtoul(*newval, NULL, 0);
+		if (errno == EINVAL || errno == ERANGE)
+		{
+			GUC_check_errdetail("recovery_target_timeline is not a valid number: \"%s\"",
+								*newval);
+			return false;
+		}
+		rttg = RECOVERY_TARGET_TIMELINE_NUMERIC;
+	}
+
+	myextra = (TimeLineID *) guc_malloc(ERROR, sizeof(TimeLineID));
+	*myextra = rttg;
+	*extra = (void *) myextra;
+
+	return true;
+}
+
+static void
+assign_recovery_target_timeline(const char *newval, void *extra)
+{
+	recoveryTargetTimeLineGoal = *((TimeLineID *) extra);
+	if (recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_NUMERIC)
+		recoveryTargetTLIRequested = (TimeLineID) strtoul(newval, NULL, 0);
+	else
+		recoveryTargetTLIRequested = 0;
+}
+
+static bool
+check_recovery_target_action(char **newval, void **extra, GucSource source)
+{
+	RecoveryTargetAction rta = RECOVERY_TARGET_ACTION_PAUSE;
+	RecoveryTargetAction *myextra;
+
+	if (strcmp(*newval, "pause") == 0)
+		rta = RECOVERY_TARGET_ACTION_PAUSE;
+	else if (strcmp(*newval, "promote") == 0)
+		rta = RECOVERY_TARGET_ACTION_PROMOTE;
+	else if (strcmp(*newval, "shutdown") == 0)
+		rta = RECOVERY_TARGET_ACTION_SHUTDOWN;
+	else if (strcmp(*newval, "") != 0)
+	{
+		GUC_check_errdetail("recovery_target_action is not valid: \"%s\"", *newval);
+		return false;
+	}
+
+	myextra = (RecoveryTargetAction *) guc_malloc(ERROR, sizeof(RecoveryTargetAction));
+	*myextra = rta;
+	*extra = (void *) myextra;
+
+	return true;
+}
+
+static void
+assign_recovery_target_action(const char *newval, void *extra)
+{
+	recoveryTargetAction = *((RecoveryTargetAction *) extra);
+}
+
+static bool
+check_sender_slot_name(char **newval, void **extra, GucSource source)
+{
+	if (strcmp(*newval,"") != 0 &&
+		!ReplicationSlotValidateName(*newval, WARNING))
+	{
+		GUC_check_errdetail("sender_slot_name is not valid: \"%s\"", *newval);
+		return false;
+	}
+
+	return true;
+}
+
 #include "guc-file.c"
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index ee8232f..2ee3bca 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -45,6 +45,9 @@
 #ident_file = 'ConfigDir/pg_ident.conf'	# ident configuration file
 					# (change requires restart)
 
+#signal_file_directory = 'ConfigDir' # signal files for recovery/replication
+					# (change requires restart)
+
 # If external_pid_file is not explicitly set, no extra PID file is written.
 #external_pid_file = ''			# write an extra PID file
 					# (change requires restart)
@@ -221,6 +224,26 @@
 #archive_timeout = 0		# force a logfile segment switch after this
 				# number of seconds; 0 disables
 
+# - Archive Recovery -
+#restore_command = ''		# command to use to restore an archived logfile segment
+				# placeholders: %p = path of file to restore
+				#               %f = file name only
+				# e.g. 'cp /mnt/server/archivedir/%f %p'
+#archive_cleanup_command = ''	# command to execute at every restartpoint
+#recovery_end_command = ''	# command to execute at completion of recovery
+
+# - Recovery Target -
+
+# Set these only when performing a targeted recovery
+
+#recovery_target_type=''	# 'xid', 'time', 'name', 'lsn',
+				# or 'immediate'
+#recovery_target_value=''	# value interpreted according to type
+#recovery_target_inclusive = on
+#recovery_target_timeline = ''	# unset means read from controlfile (default),
+				# or set to 'latest' or timeline ID
+#recovery_target_action = '' 	# 'pause', 'promote', 'shutdown'
+
 
 #------------------------------------------------------------------------------
 # REPLICATION
@@ -254,6 +277,8 @@
 
 # These settings are ignored on a master server.
 
+#sender_conninfo = ''			# connection string on sending server
+#sender_slot_name = ''			# connection slot on sending server
 #hot_standby = off			# "on" allows queries during recovery
 					# (change requires restart)
 #max_standby_archive_delay = 30s	# max delay before canceling queries
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 7d21408..8b6dfca 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -87,6 +87,41 @@ typedef enum
 	RECOVERY_TARGET_IMMEDIATE
 } RecoveryTargetType;
 
+#define RecoveryTargetText(t) ( \
+	t == RECOVERY_TARGET_UNSET ? "unset" : ( \
+	t == RECOVERY_TARGET_XID   ? "xid" : ( \
+	t == RECOVERY_TARGET_TIME  ? "timestamp" : ( \
+	t == RECOVERY_TARGET_NAME  ? "name" : ( \
+	t == RECOVERY_TARGET_LSN   ? "lsn" : \
+					"immediate" )))))
+
+/*
+ * Recovery target action.
+ */
+typedef enum
+{
+	RECOVERY_TARGET_ACTION_PAUSE,
+	RECOVERY_TARGET_ACTION_PROMOTE,
+	RECOVERY_TARGET_ACTION_SHUTDOWN
+} RecoveryTargetAction;
+
+#define RecoveryTargetActionText(t) ( \
+	t == RECOVERY_TARGET_ACTION_PAUSE   ? "pause" : ( \
+	t == RECOVERY_TARGET_ACTION_PROMOTE ? "promote" : ( \
+						"shutdown" )))
+/*
+ * Recovery target TimeLine goal
+ */
+typedef enum
+{
+	RECOVERY_TARGET_TIMELINE_CONTROLFILE,
+	RECOVERY_TARGET_TIMELINE_LATEST,
+	RECOVERY_TARGET_TIMELINE_NUMERIC
+} RecoveryTargetTimeLineGoal;
+
+/* Max length of named restore points */
+#define MAXRESTOREPOINTNAMELEN 64
+
 extern XLogRecPtr ProcLastRecPtr;
 extern XLogRecPtr XactLastRecEnd;
 extern PGDLLIMPORT XLogRecPtr XactLastCommitEnd;
@@ -109,6 +144,36 @@ extern bool log_checkpoints;
 
 extern int	CheckPointSegments;
 
+/* options previously taken from recovery.conf for archive recovery */
+extern char *recoveryRestoreCommand;
+extern char *recoveryEndCommand;
+extern char *archiveCleanupCommand;
+extern char *recoveryTargetTypeString;
+extern RecoveryTargetType recoveryTarget;
+extern char *recoveryTargetValue;
+extern bool recoveryTargetInclusive;
+extern RecoveryTargetAction recoveryTargetAction;
+extern TransactionId recoveryTargetXid;
+extern TimestampTz recoveryTargetTime;
+extern char *recoveryTargetName;
+extern XLogRecPtr recoveryTargetLSN;
+extern int     recovery_min_apply_delay;
+
+/* option set locally in Startup process only when signal files exist */
+extern bool StandbyModeRequested;
+extern bool StandbyMode;
+
+/* options for WALreceiver.c */
+extern char *SenderConnInfo;
+extern char *SenderSlotName;
+
+extern char *signal_file_directory;
+
+extern char *recoveryTargetTLIString;
+extern RecoveryTargetTimeLineGoal recoveryTargetTimeLineGoal;
+extern TimeLineID recoveryTargetTLIRequested;
+extern TimeLineID recoveryTargetTLI;
+
 /* Archive modes */
 typedef enum ArchiveMode
 {
@@ -238,6 +303,7 @@ extern const char *xlog_identify(uint8 info);
 
 extern void issue_xlog_fsync(int fd, XLogSegNo segno);
 
+extern void validateRecoveryParameters(void);
 extern bool RecoveryInProgress(void);
 extern bool HotStandbyActive(void);
 extern bool HotStandbyActiveInReplay(void);
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 05f996b..1a80377 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -246,16 +246,6 @@ typedef struct XLogRecData
 } XLogRecData;
 
 /*
- * Recovery target action.
- */
-typedef enum
-{
-	RECOVERY_TARGET_ACTION_PAUSE,
-	RECOVERY_TARGET_ACTION_PROMOTE,
-	RECOVERY_TARGET_ACTION_SHUTDOWN
-} RecoveryTargetAction;
-
-/*
  * Method table for resource managers.
  *
  * This struct must be kept in sync with the PG_RMGR definition in
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index b695f61..7f4389c 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -68,6 +68,8 @@ enum config_group
 	WAL_SETTINGS,
 	WAL_CHECKPOINTS,
 	WAL_ARCHIVING,
+	WAL_ARCHIVE_RECOVERY,
+	WAL_RECOVERY_TARGET,
 	REPLICATION,
 	REPLICATION_SENDING,
 	REPLICATION_MASTER,
diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm
index c1b16ca..60ad78e 100644
--- a/src/test/perl/PostgresNode.pm
+++ b/src/test/perl/PostgresNode.pm
@@ -574,8 +574,6 @@ of a backup previously created on that node with $node->backup.
 
 Does not start the node after initializing it.
 
-A recovery.conf is not created.
-
 pg_hba.conf is configured to allow replication connections. Pass the keyword
 parameter hba_permit_replication => 0 to disable this.
 
@@ -745,13 +743,16 @@ sub enable_streaming
 	my ($self, $root_node) = @_;
 	my $root_connstr = $root_node->connstr;
 	my $name         = $self->name;
+	my $pgdata  = $self->data_dir;
 
 	print "### Enabling streaming replication for node \"$name\"\n";
 	$self->append_conf(
-		'recovery.conf', qq(
-primary_conninfo='$root_connstr application_name=$name'
-standby_mode=on
+		'postgresql.conf', qq(
+sender_conninfo='$root_connstr application_name=$name'
 ));
+	open my $standbysignal, ">>$pgdata/standby.signal";
+	print $standbysignal "\n# Allow replication (set up by PostgresNode.pm)\n";
+	close $standbysignal;
 }
 
 # Internal routine to enable archive recovery command on a standby node
@@ -760,6 +761,7 @@ sub enable_restoring
 	my ($self, $root_node) = @_;
 	my $path = $root_node->archive_dir;
 	my $name = $self->name;
+	my $pgdata  = $self->data_dir;
 
 	print "### Enabling WAL restore for node \"$name\"\n";
 
@@ -776,10 +778,12 @@ sub enable_restoring
 	  : qq{cp "$path/%f" "%p"};
 
 	$self->append_conf(
-		'recovery.conf', qq(
+		'postgresql.conf', qq(
 restore_command = '$copy_command'
-standby_mode = on
 ));
+	open my $recoverysignal, ">>$pgdata/recovery.signal";
+	print $recoverysignal "\n# Allow recovery (set up by PostgresNode.pm)\n";
+	close $recoverysignal;
 }
 
 # Internal routine to enable archiving
diff --git a/src/test/recovery/t/003_recovery_targets.pl b/src/test/recovery/t/003_recovery_targets.pl
index a82545b..236e651 100644
--- a/src/test/recovery/t/003_recovery_targets.pl
+++ b/src/test/recovery/t/003_recovery_targets.pl
@@ -3,7 +3,7 @@ use strict;
 use warnings;
 use PostgresNode;
 use TestLib;
-use Test::More tests => 9;
+use Test::More tests => 5;
 
 # Create and test a standby from given backup, with a certain
 # recovery target.
@@ -23,7 +23,7 @@ sub test_recovery_standby
 	foreach my $param_item (@$recovery_params)
 	{
 		$node_standby->append_conf(
-			'recovery.conf',
+			'postgresql.conf',
 			qq($param_item
 ));
 	}
@@ -100,47 +100,20 @@ $node_master->safe_psql('postgres',
 $node_master->safe_psql('postgres', "SELECT pg_switch_xlog()");
 
 # Test recovery targets
-my @recovery_params = ("recovery_target = 'immediate'");
+my @recovery_params = ("recovery_target_type = 'immediate'");
 test_recovery_standby('immediate target',
 	'standby_1', $node_master, \@recovery_params, "1000", $lsn1);
-@recovery_params = ("recovery_target_xid = '$recovery_txid'");
+@recovery_params = ("recovery_target_type = 'xid'", "recovery_target_value = '$recovery_txid'");
 test_recovery_standby('XID', 'standby_2', $node_master, \@recovery_params,
 	"2000", $lsn2);
-@recovery_params = ("recovery_target_time = '$recovery_time'");
+@recovery_params = ("recovery_target_type = 'timestamp'", "recovery_target_value = '$recovery_time'");
 test_recovery_standby('time', 'standby_3', $node_master, \@recovery_params,
 	"3000", $lsn3);
-@recovery_params = ("recovery_target_name = '$recovery_name'");
+@recovery_params = ("recovery_target_type = 'name'", "recovery_target_value = '$recovery_name'");
 test_recovery_standby('name', 'standby_4', $node_master, \@recovery_params,
 	"4000", $lsn4);
-@recovery_params = ("recovery_target_lsn = '$recovery_lsn'");
+@recovery_params = ("recovery_target_type = 'lsn'", "recovery_target_value = '$recovery_lsn'");
 test_recovery_standby('LSN', 'standby_5', $node_master, \@recovery_params,
 	"5000", $lsn5);
 
-# Multiple targets
-# Last entry has priority (note that an array respects the order of items
-# not hashes).
-@recovery_params = (
-	"recovery_target_name = '$recovery_name'",
-	"recovery_target_xid  = '$recovery_txid'",
-	"recovery_target_time = '$recovery_time'");
-test_recovery_standby('name + XID + time',
-	'standby_6', $node_master, \@recovery_params, "3000", $lsn3);
-@recovery_params = (
-	"recovery_target_time = '$recovery_time'",
-	"recovery_target_name = '$recovery_name'",
-	"recovery_target_xid  = '$recovery_txid'");
-test_recovery_standby('time + name + XID',
-	'standby_7', $node_master, \@recovery_params, "2000", $lsn2);
-@recovery_params = (
-	"recovery_target_xid  = '$recovery_txid'",
-	"recovery_target_time = '$recovery_time'",
-	"recovery_target_name = '$recovery_name'");
-test_recovery_standby('XID + time + name',
-	'standby_8', $node_master, \@recovery_params, "4000", $lsn4);
-@recovery_params = (
-	"recovery_target_xid  = '$recovery_txid'",
-	"recovery_target_time = '$recovery_time'",
-	"recovery_target_name = '$recovery_name'",
-	"recovery_target_lsn = '$recovery_lsn'",);
-test_recovery_standby('XID + time + name + LSN',
-	'standby_9', $node_master, \@recovery_params, "5000", $lsn5);
+# Tests for multiple targets no longer needed from 10.0 onwards
diff --git a/src/test/recovery/t/004_timeline_switch.pl b/src/test/recovery/t/004_timeline_switch.pl
index 5f3b2fe..d73ffa6 100644
--- a/src/test/recovery/t/004_timeline_switch.pl
+++ b/src/test/recovery/t/004_timeline_switch.pl
@@ -46,12 +46,10 @@ $node_master->teardown_node;
 $node_standby_1->promote;
 
 # Switch standby 2 to replay from standby 1
-rmtree($node_standby_2->data_dir . '/recovery.conf');
 my $connstr_1 = $node_standby_1->connstr;
 $node_standby_2->append_conf(
-	'recovery.conf', qq(
-primary_conninfo='$connstr_1'
-standby_mode=on
+	'postgresql.conf', qq(
+sender_conninfo='$connstr_1'
 recovery_target_timeline='latest'
 ));
 $node_standby_2->restart;
diff --git a/src/test/recovery/t/005_replay_delay.pl b/src/test/recovery/t/005_replay_delay.pl
index 640295b..ab87faf 100644
--- a/src/test/recovery/t/005_replay_delay.pl
+++ b/src/test/recovery/t/005_replay_delay.pl
@@ -25,7 +25,7 @@ my $delay        = 3;
 $node_standby->init_from_backup($node_master, $backup_name,
 	has_streaming => 1);
 $node_standby->append_conf(
-	'recovery.conf', qq(
+	'postgresql.conf', qq(
 recovery_min_apply_delay = '${delay}s'
 ));
 $node_standby->start;
