diff --git a/src/bin/pg_rewind/Makefile b/src/bin/pg_rewind/Makefile
index 7a97df6..b214501 100644
--- a/src/bin/pg_rewind/Makefile
+++ b/src/bin/pg_rewind/Makefile
@@ -18,9 +18,12 @@ include $(top_builddir)/src/Makefile.global
 override CPPFLAGS := -I$(libpq_srcdir) -DFRONTEND $(CPPFLAGS)
 LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport)
 
+ENCRYPTIONSOURCES = $(sort $(notdir $(wildcard $(top_srcdir)/src/backend/storage/encryption/*.c)))
+ENCRYPTIONOBJS = $(patsubst %.c,%.o,$(ENCRYPTIONSOURCES))
+
 OBJS	= pg_rewind.o parsexlog.o xlogreader.o datapagemap.o timeline.o \
-	fetch.o file_ops.o copy_fetch.o libpq_fetch.o filemap.o \
-	$(WIN32RES)
+	fetch.o file_ops.o copy_fetch.o libpq_fetch.o filemap.o compat.o \
+	$(ENCRYPTIONOBJS) $(WIN32RES)
 
 EXTRA_CLEAN = xlogreader.c
 
@@ -32,6 +35,9 @@ pg_rewind: $(OBJS) | submake-libpq submake-libpgport
 xlogreader.c: % : $(top_srcdir)/src/backend/access/transam/%
 	rm -f $@ && $(LN_S) $< .
 
+$(ENCRYPTIONSOURCES): % : $(top_srcdir)/src/backend/storage/encryption/%
+	rm -f $@ && $(LN_S) $< .
+
 install: all installdirs
 	$(INSTALL_PROGRAM) pg_rewind$(X) '$(DESTDIR)$(bindir)/pg_rewind$(X)'
 
@@ -42,7 +48,7 @@ uninstall:
 	rm -f '$(DESTDIR)$(bindir)/pg_rewind$(X)'
 
 clean distclean maintainer-clean:
-	rm -f pg_rewind$(X) $(OBJS) xlogreader.c
+	rm -f pg_rewind$(X) $(OBJS) $(ENCRYPTIONSOURCES) xlogreader.c
 	rm -rf tmp_check
 
 check:
diff --git a/src/bin/pg_rewind/compat.c b/src/bin/pg_rewind/compat.c
new file mode 100644
index 0000000..1555176
--- /dev/null
+++ b/src/bin/pg_rewind/compat.c
@@ -0,0 +1,125 @@
+/*-------------------------------------------------------------------------
+ *
+ * compat.c
+ *		Reimplementations of various backend functions.
+ *
+ * Portions Copyright (c) 2013-2019, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *		src/bin/pg_waldump/compat.c
+ *
+ * This file contains client-side implementations for various backend
+ * functions that the rm_desc functions in *desc.c files rely on.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/* ugly hack, same as in e.g pg_controldata */
+#define FRONTEND 1
+#include "postgres.h"
+
+#include <time.h>
+
+#include "lib/stringinfo.h"
+#include "utils/datetime.h"
+#include "common/logging.h"
+
+/* copied from timestamp.c */
+pg_time_t
+timestamptz_to_time_t(TimestampTz t)
+{
+	pg_time_t	result;
+
+	result = (pg_time_t) (t / USECS_PER_SEC +
+						  ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY));
+	return result;
+}
+
+/*
+ * Stopgap implementation of timestamptz_to_str that doesn't depend on backend
+ * infrastructure.  This will work for timestamps that are within the range
+ * of the platform time_t type.  (pg_time_t is compatible except for possibly
+ * being wider.)
+ *
+ * XXX the return value points to a static buffer, so beware of using more
+ * than one result value concurrently.
+ *
+ * XXX: The backend timestamp infrastructure should instead be split out and
+ * moved into src/common.  That's a large project though.
+ */
+const char *
+timestamptz_to_str(TimestampTz dt)
+{
+	static char buf[MAXDATELEN + 1];
+	char		ts[MAXDATELEN + 1];
+	char		zone[MAXDATELEN + 1];
+	time_t		result = (time_t) timestamptz_to_time_t(dt);
+	struct tm  *ltime = localtime(&result);
+
+	strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S", ltime);
+	strftime(zone, sizeof(zone), "%Z", ltime);
+
+	snprintf(buf, sizeof(buf), "%s.%06d %s",
+			 ts, (int) (dt % USECS_PER_SEC), zone);
+
+	return buf;
+}
+
+/*
+ * Provide a hacked up compat layer for StringInfos so xlog desc functions can
+ * be linked/called.
+ */
+void
+initStringInfo(StringInfo str)
+{
+	int size = 1024;    /* initial default buffer size */
+
+	str->data = (char *) palloc(size);
+	str->maxlen = size;
+	str->data[0] = '\0';
+	str->len = 0;
+	str->cursor = 0;
+}
+
+void
+appendStringInfo(StringInfo str, const char *fmt,...)
+{
+	va_list		args;
+
+	va_start(args, fmt);
+	if (str)
+	{
+		int		avail;
+		size_t		nprinted;
+
+		avail = str->maxlen - str->len;
+		nprinted = pvsnprintf(str->data + str->len, (size_t) avail, fmt, args);
+
+		if (nprinted < (size_t) avail)
+		{
+			/* Success.  Note nprinted does not include trailing null. */
+			str->len += (int) nprinted;
+		}
+		else
+		{
+			pg_log_error("the string is too long");
+			exit(1);
+		}
+
+	}
+	else
+	vprintf(fmt, args);
+	va_end(args);
+}
+
+void
+appendStringInfoString(StringInfo str, const char *string)
+{
+	appendStringInfo(str, "%s", string);
+}
+
+void
+appendStringInfoChar(StringInfo str, char ch)
+{
+	appendStringInfo(str, "%c", ch);
+}
diff --git a/src/bin/pg_rewind/parsexlog.c b/src/bin/pg_rewind/parsexlog.c
index 1d03375..e3557de 100644
--- a/src/bin/pg_rewind/parsexlog.c
+++ b/src/bin/pg_rewind/parsexlog.c
@@ -21,6 +21,8 @@
 #include "commands/dbcommands_xlog.h"
 #include "filemap.h"
 #include "pg_rewind.h"
+#include "catalog/pg_control.h"
+#include "storage/encryption.h"
 
 /*
  * RmgrNames is an array of resource manager names, to make error messages
@@ -312,6 +314,18 @@ SimpleXLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
 		return -1;
 	}
 
+	if (DataEncryptionEnabled())
+	{
+		XLogSegNo       readSegNo;
+		uint32          readSegOff;
+
+		XLByteToSeg(targetPagePtr, readSegNo, WalSegSz);
+		readSegOff = targetPagePtr % WalSegSz;
+
+		DecryptXLog(readBuf, XLOG_BLCKSZ, readSegNo, readSegOff);
+	}
+
+
 	Assert(targetSegNo == xlogreadsegno);
 
 	xlogreader->seg.ws_tli = targetHistory[private->tliIndex].tli;
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index e75c7ee..370d00e 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -7,6 +7,7 @@
  *
  *-------------------------------------------------------------------------
  */
+#define FRONTEND 1
 #include "postgres_fe.h"
 
 #include <sys/stat.h>
@@ -74,6 +75,8 @@ usage(const char *progname)
 	printf(_("%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n\n"), progname);
 	printf(_("Usage:\n  %s [OPTION]...\n\n"), progname);
 	printf(_("Options:\n"));
+	printf(_("  -c  --cluster-passphrase-command=COMMAND\n"
+			"                      set command to obtain passphrase for data encryption key\n"));
 	printf(_("  -D, --target-pgdata=DIRECTORY  existing data directory to modify\n"));
 	printf(_("      --source-pgdata=DIRECTORY  source data directory to synchronize with\n"));
 	printf(_("      --source-server=CONNSTR    source server to synchronize with\n"));
@@ -96,6 +99,7 @@ main(int argc, char **argv)
 {
 	static struct option long_options[] = {
 		{"help", no_argument, NULL, '?'},
+		{"cluster-passphrase-command", required_argument, NULL, 'c'},
 		{"target-pgdata", required_argument, NULL, 'D'},
 		{"write-recovery-conf", no_argument, NULL, 'R'},
 		{"source-pgdata", required_argument, NULL, 1},
@@ -123,6 +127,7 @@ main(int argc, char **argv)
 	TimeLineID	endtli;
 	ControlFileData ControlFile_new;
 	bool		writerecoveryconf = false;
+	char       *cluster_passphrase = NULL;
 
 	pg_logging_init(argv[0]);
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_rewind"));
@@ -143,7 +148,7 @@ main(int argc, char **argv)
 		}
 	}
 
-	while ((c = getopt_long(argc, argv, "D:nNPR", long_options, &option_index)) != -1)
+	while ((c = getopt_long(argc, argv, "c:D:nNPR", long_options, &option_index)) != -1)
 	{
 		switch (c)
 		{
@@ -151,6 +156,9 @@ main(int argc, char **argv)
 				fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 				exit(1);
 
+			case 'c':
+				cluster_passphrase = pg_strdup(optarg);
+				break;
 			case 'P':
 				showprogress = true;
 				break;
@@ -242,6 +250,12 @@ main(int argc, char **argv)
 	}
 #endif
 
+	if (datadir_target)
+		getKmgr(datadir_target, cluster_passphrase, progname);
+	if (datadir_source)
+		getKmgr(datadir_source, cluster_passphrase, progname);
+
+
 	get_restricted_token();
 
 	/* Set mask based on PGDATA permissions */
diff --git a/src/bin/pg_rewind/t/007_basic_tde.pl b/src/bin/pg_rewind/t/007_basic_tde.pl
new file mode 100644
index 0000000..127dbf6
--- /dev/null
+++ b/src/bin/pg_rewind/t/007_basic_tde.pl
@@ -0,0 +1,175 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 11;
+
+use FindBin;
+use lib $FindBin::RealBin;
+
+use RewindTest;
+
+sub run_test
+{
+	my $test_mode = shift;
+
+	RewindTest::setup_cluster($test_mode);
+	RewindTest::start_master();
+
+	# Create a test table and insert a row in master.
+	master_psql("CREATE TABLE tbl1 (d text)");
+	master_psql("INSERT INTO tbl1 VALUES ('in master')");
+
+	# This test table will be used to test truncation, i.e. the table
+	# is extended in the old master after promotion
+	master_psql("CREATE TABLE trunc_tbl (d text)");
+	master_psql("INSERT INTO trunc_tbl VALUES ('in master')");
+
+	# This test table will be used to test the "copy-tail" case, i.e. the
+	# table is truncated in the old master after promotion
+	master_psql("CREATE TABLE tail_tbl (id integer, d text)");
+	master_psql("INSERT INTO tail_tbl VALUES (0, 'in master')");
+
+	master_psql("CHECKPOINT");
+
+	RewindTest::create_standby($test_mode);
+
+	# Insert additional data on master that will be replicated to standby
+	master_psql("INSERT INTO tbl1 values ('in master, before promotion')");
+	master_psql(
+		"INSERT INTO trunc_tbl values ('in master, before promotion')");
+	master_psql(
+		"INSERT INTO tail_tbl SELECT g, 'in master, before promotion: ' || g FROM generate_series(1, 10000) g"
+	);
+
+	master_psql('CHECKPOINT');
+
+	RewindTest::promote_standby();
+
+	# Insert a row in the old master. This causes the master and standby
+	# to have "diverged", it's no longer possible to just apply the
+	# standy's logs over master directory - you need to rewind.
+	master_psql("INSERT INTO tbl1 VALUES ('in master, after promotion')");
+
+	# Also insert a new row in the standby, which won't be present in the
+	# old master.
+	standby_psql("INSERT INTO tbl1 VALUES ('in standby, after promotion')");
+
+	# Insert enough rows to trunc_tbl to extend the file. pg_rewind should
+	# truncate it back to the old size.
+	master_psql(
+		"INSERT INTO trunc_tbl SELECT 'in master, after promotion: ' || g FROM generate_series(1, 10000) g"
+	);
+
+	# Truncate tail_tbl. pg_rewind should copy back the truncated part
+	# (We cannot use an actual TRUNCATE command here, as that creates a
+	# whole new relfilenode)
+	master_psql("DELETE FROM tail_tbl WHERE id > 10");
+	master_psql("VACUUM tail_tbl");
+
+	# Before running pg_rewind, do a couple of extra tests with several
+	# option combinations.  As the code paths taken by those tests
+	# do not change for the "local" and "remote" modes, just run them
+	# in "local" mode for simplicity's sake.
+	if ($test_mode eq 'local')
+	{
+		my $master_pgdata  = $node_master->data_dir;
+		my $standby_pgdata = $node_standby->data_dir;
+
+		# First check that pg_rewind fails if the target cluster is
+		# not stopped as it fails to start up for the forced recovery
+		# step.
+		command_fails(
+			[
+				'pg_rewind',       '--debug',
+				'--source-pgdata', $standby_pgdata,
+				'--target-pgdata', $master_pgdata,
+				'--no-sync'
+			],
+			'pg_rewind with running target');
+
+		# Again with --no-ensure-shutdown, which should equally fail.
+		# This time pg_rewind complains without attempting to perform
+		# recovery once.
+		command_fails(
+			[
+				'pg_rewind',       '--debug',
+				'--source-pgdata', $standby_pgdata,
+				'--target-pgdata', $master_pgdata,
+				'--no-sync',       '--no-ensure-shutdown'
+			],
+			'pg_rewind --no-ensure-shutdown with running target');
+
+		# Stop the target, and attempt to run with a local source
+		# still running.  This fails as pg_rewind requires to have
+		# a source cleanly stopped.
+		$node_master->stop;
+		command_fails(
+			[
+				'pg_rewind',       '--debug',
+				'--source-pgdata', $standby_pgdata,
+				'--target-pgdata', $master_pgdata,
+				'--no-sync',       '--no-ensure-shutdown'
+			],
+			'pg_rewind with unexpected running source');
+
+		# Stop the target cluster cleanly, and run again pg_rewind
+		# with --dry-run mode.  If anything gets generated in the data
+		# folder, the follow-up run of pg_rewind will most likely fail,
+		# so keep this test as the last one of this subset.
+		$node_standby->stop;
+		command_ok(
+			[
+				'pg_rewind',       '--debug',
+				'--source-pgdata', $standby_pgdata,
+				'--target-pgdata', $master_pgdata,
+				'--no-sync',       '--dry-run'
+			],
+			'pg_rewind --dry-run');
+
+		# Both clusters need to be alive moving forward.
+		$node_standby->start;
+		$node_master->start;
+	}
+
+	RewindTest::run_pg_rewind($test_mode);
+
+	check_query(
+		'SELECT * FROM tbl1',
+		qq(in master
+in master, before promotion
+in standby, after promotion
+),
+		'table content');
+
+	check_query(
+		'SELECT * FROM trunc_tbl',
+		qq(in master
+in master, before promotion
+),
+		'truncation');
+
+	check_query(
+		'SELECT count(*) FROM tail_tbl',
+		qq(10001
+),
+		'tail-copy');
+
+	# Permissions on PGDATA should be default
+  SKIP:
+	{
+		skip "unix-style permissions not supported on Windows", 1
+		  if ($windows_os);
+
+		ok(check_mode_recursive($node_master->data_dir(), 0700, 0600),
+			'check PGDATA permissions');
+	}
+
+	RewindTest::clean_rewind_test();
+	return;
+}
+
+# Run the test in both modes
+run_test('local-tde');
+run_test('remote-tde');
+
+exit(0);
diff --git a/src/bin/pg_rewind/t/RewindTest.pm b/src/bin/pg_rewind/t/RewindTest.pm
index 82fa220..43ea17a 100644
--- a/src/bin/pg_rewind/t/RewindTest.pm
+++ b/src/bin/pg_rewind/t/RewindTest.pm
@@ -129,10 +129,21 @@ sub setup_cluster
 	# Set up pg_hba.conf and pg_ident.conf for the role running
 	# pg_rewind.  This role is used for all the tests, and has
 	# minimal permissions enough to rewind from an online source.
-	$node_master->init(
-		allows_streaming => 1,
-		extra            => $extra,
-		auth_extra       => [ '--create-role', 'rewind_user' ]);
+	if (($extra_name eq "local-tde") or ($extra_name eq "remote-tde"))
+	{
+		$node_master->init(
+			allows_streaming => 1,
+			extra            => $extra,
+			auth_extra       => [ '--create-role', 'rewind_user' ],
+			enable_encryption	=> 1);
+	}
+	else
+	{
+		$node_master->init(
+			allows_streaming => 1,
+			extra            => $extra,
+			auth_extra       => [ '--create-role', 'rewind_user' ]);
+	}
 
 	# Set wal_keep_segments to prevent WAL segment recycling after enforced
 	# checkpoints in the tests.
@@ -284,6 +295,40 @@ sub run_pg_rewind
 		$node_standby->safe_psql('postgres',
 			"ALTER ROLE rewind_user WITH REPLICATION;");
 	}
+	elsif ($test_mode eq "local-tde")
+	{
+
+		$node_standby->stop;
+		command_ok(
+			[
+				'pg_rewind',
+				"--debug",
+				"--cluster-passphrase-command", 'echo "password"',
+				"--source-pgdata=$standby_pgdata",
+				"--target-pgdata=$master_pgdata",
+				"--no-sync"
+			],
+			'pg_rewind local');
+	}
+	elsif ($test_mode eq "remote-tde")
+	{
+
+		command_ok(
+			[
+				'pg_rewind',                      "--debug",
+				"--cluster-passphrase-command", 'echo "password"',
+				"--source-server",                $standby_connstr,
+				"--target-pgdata=$master_pgdata", "--no-sync",
+				"--write-recovery-conf"
+			],
+			'pg_rewind remote');
+
+		ok( -e "$master_pgdata/standby.signal",
+			'standby.signal created after pg_rewind');
+
+		$node_standby->safe_psql('postgres',
+			"ALTER ROLE rewind_user WITH REPLICATION;");
+	}
 	else
 	{
 
