diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c
index 0293115054f07e8a54f62020484b7939b9590ef6..9816f550ca57cd9af4e07bc2f2bc1c96cde50ec7 100644
--- a/contrib/postgres_fdw/deparse.c
+++ b/contrib/postgres_fdw/deparse.c
@@ -456,6 +456,29 @@ appendWhereClause(StringInfo buf,
 	}
 }
 
+/*
+ * Construct SELECT statement to acquire size in blocks of given relation.
+ *
+ * Note: we use local definition of block size, not remote definition.
+ * This is perhaps debatable.
+ *
+ * Note: pg_relation_size() exists in 8.1 and later.
+ */
+void
+deparseAnalyzeSizeSql(StringInfo buf, Relation rel)
+{
+	Oid			relid = RelationGetRelid(rel);
+	StringInfoData relname;
+
+	/* We'll need the remote relation name as a literal. */
+	initStringInfo(&relname);
+	deparseRelation(&relname, relid);
+
+	appendStringInfo(buf, "SELECT pg_catalog.pg_relation_size(");
+	deparseStringLiteral(buf, relname.data);
+	appendStringInfo(buf, "::pg_catalog.regclass) / %d", BLCKSZ);
+}
+
 /*
  * Construct SELECT statement to acquire sample rows of given relation.
  *
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index a3256179f2bee9db0446dbc7c3125177fe0fd3b4..99dc6aef135c018616a08a13e12b12cf8fd9bed2 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -259,6 +259,9 @@ postgresGetForeignRelSize(PlannerInfo *root,
 	int			width;
 	Cost		startup_cost;
 	Cost		total_cost;
+	Cost		run_cost;
+	QualCost	qpqual_cost;
+	Cost		cpu_per_tuple;
 	List	   *remote_conds;
 	List	   *param_conds;
 	List	   *local_conds;
@@ -349,6 +352,16 @@ postgresGetForeignRelSize(PlannerInfo *root,
 		sel *= clauselist_selectivity(root, local_conds,
 									  baserel->relid, JOIN_INNER, NULL);
 
+		/*
+		 * Add in the eval cost of those conditions, too.
+		 */
+		cost_qual_eval(&qpqual_cost, param_conds, root);
+		startup_cost += qpqual_cost.startup;
+		total_cost += qpqual_cost.per_tuple * rows;
+		cost_qual_eval(&qpqual_cost, local_conds, root);
+		startup_cost += qpqual_cost.startup;
+		total_cost += qpqual_cost.per_tuple * rows;
+
 		/* Report estimated numbers to planner. */
 		baserel->rows = clamp_row_est(rows * sel);
 		baserel->width = width;
@@ -367,18 +380,25 @@ postgresGetForeignRelSize(PlannerInfo *root,
 		 * estimate of 10 pages, and divide by the column-datatype-based width
 		 * estimate to get the corresponding number of tuples.
 		 */
-		if (baserel->tuples <= 0)
+		if (baserel->pages == 0 && baserel->tuples == 0)
+		{
+			baserel->pages = 10;
 			baserel->tuples =
 				(10 * BLCKSZ) / (baserel->width + sizeof(HeapTupleHeaderData));
+		}
 
 		set_baserel_size_estimates(root, baserel);
 
-		/*
-		 * XXX need to do something here to calculate sane startup and total
-		 * cost estimates ... for the moment, we do this:
-		 */
+		/* Cost as though this were a seqscan, which is pessimistic. */
 		startup_cost = 0;
-		total_cost = baserel->rows * cpu_tuple_cost;
+		run_cost = 0;
+		run_cost += seq_page_cost * baserel->pages;
+
+		startup_cost += baserel->baserestrictcost.startup;
+		cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost.per_tuple;
+		run_cost += cpu_per_tuple * baserel->tuples;
+
+		total_cost = startup_cost + run_cost;
 	}
 
 	/*
@@ -1068,9 +1088,62 @@ postgresAnalyzeForeignTable(Relation relation,
 							AcquireSampleRowsFunc *func,
 							BlockNumber *totalpages)
 {
-	*totalpages = 0;			/* XXX this is probably a bad idea */
+	ForeignTable *table;
+	ForeignServer *server;
+	UserMapping *user;
+	PGconn	   *conn;
+	StringInfoData sql;
+	PGresult   *volatile res = NULL;
+
+	/* Return the row-analysis function pointer */
 	*func = postgresAcquireSampleRowsFunc;
 
+	/*
+	 * Now we have to get the number of pages.  It's annoying that the ANALYZE
+	 * API requires us to return that now, because it forces some duplication
+	 * of effort between this routine and postgresAcquireSampleRowsFunc.  But
+	 * it's probably not worth redefining that API at this point.
+	 */
+
+	/*
+	 * Get the connection to use.  We do the remote access as the table's
+	 * owner, even if the ANALYZE was started by some other user.
+	 */
+	table = GetForeignTable(RelationGetRelid(relation));
+	server = GetForeignServer(table->serverid);
+	user = GetUserMapping(relation->rd_rel->relowner, server->serverid);
+	conn = GetConnection(server, user);
+
+	/*
+	 * Construct command to get page count for relation.
+	 */
+	initStringInfo(&sql);
+	deparseAnalyzeSizeSql(&sql, relation);
+
+	/* In what follows, do not risk leaking any PGresults. */
+	PG_TRY();
+	{
+		res = PQexec(conn, sql.data);
+		if (PQresultStatus(res) != PGRES_TUPLES_OK)
+			pgfdw_report_error(ERROR, res, false, sql.data);
+
+		if (PQntuples(res) != 1 || PQnfields(res) != 1)
+			elog(ERROR, "unexpected result from deparseAnalyzeSizeSql query");
+		*totalpages = strtoul(PQgetvalue(res, 0, 0), NULL, 10);
+
+		PQclear(res);
+		res = NULL;
+	}
+	PG_CATCH();
+	{
+		if (res)
+			PQclear(res);
+		PG_RE_THROW();
+	}
+	PG_END_TRY();
+
+	ReleaseConnection(conn);
+
 	return true;
 }
 
diff --git a/contrib/postgres_fdw/postgres_fdw.h b/contrib/postgres_fdw/postgres_fdw.h
index 52d1d49b25e2a5268d4cdafc8aaebf150a5b29a3..940b81a7398f9d1047bb775348035527b3291be3 100644
--- a/contrib/postgres_fdw/postgres_fdw.h
+++ b/contrib/postgres_fdw/postgres_fdw.h
@@ -47,6 +47,7 @@ extern void appendWhereClause(StringInfo buf,
 				  bool has_where,
 				  List *exprs,
 				  PlannerInfo *root);
+extern void deparseAnalyzeSizeSql(StringInfo buf, Relation rel);
 extern void deparseAnalyzeSql(StringInfo buf, Relation rel);
 
 #endif   /* POSTGRES_FDW_H */