diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index eeba2caa43..9298e03add 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -8024,6 +8024,66 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
       </listitem>
      </varlistentry>

+     <varlistentry id="guc-autovacuum-analyze-attach-partition" xreflabel="autovacuum_analyze_attach_partition">
+      <term><varname>autovacuum_analyze_attach_partition</varname> (<type>boolean</type>)
+      <indexterm>
+       <primary><varname>autovacuum_analyze_attach_partition</varname></primary>
+       <secondary>configuration parameter</secondary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Controls whether <command>ATTACH PARTITION</command> commands are counted
+        as the changed tuples for partitioned tables.  The default value is on.
+        If on, the number of tuples of the attached partition is counted in its
+        ancestors' changed tuples.
+        This parameter can only be set in the <filename>postgresql.conf</filename>
+        file or on the server command line; but this can be
+        disabled for individual tables by changing table storage parameters.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-autovacuum-analyze-detach-partition" xreflabel="autovacuum_analyze_detach_partition">
+      <term><varname>autovacuum_analyze_detach_partition</varname> (<type>boolean</type>)
+      <indexterm>
+       <primary><varname>autovacuum_analyze_detach_partition</varname></primary>
+       <secondary>configuration parameter</secondary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Controls whether <command>DETACH PARTITION</command> commands are counted
+        as the changed tuples for partitioned tables.  The default value is on.
+        If on, the number of tuples of the detached partition is counted in its
+        ancestors' changed tuples.
+        This parameter can only be set in the <filename>postgresql.conf</filename>
+        file or on the server command line; but this can be
+        disabled for individual tables by changing table storage parameters.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-autovacuum-analyze-drop-partition" xreflabel="autovacuum_analyze_drop_partition">
+      <term><varname>autovacuum_analyze_drop_partition</varname> (<type>boolean</type>)
+      <indexterm>
+       <primary><varname>autovacuum_analyze_drop_partition</varname></primary>
+       <secondary>configuration parameter</secondary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Controls whether <command>DROP TABLE</command> commands executed on partitions
+        are counted as the changed tuples for partitioned tables.  The default value is
+        on.  If on, the number of tuples of the dropped partition is counted in its
+        ancestors' changed tuples.
+        This parameter can only be set in the <filename>postgresql.conf</filename>
+        file or on the server command line; but this can be
+        disabled for individual tables by changing table storage parameters.
+       </para>
+      </listitem>
+     </varlistentry>
+
     </variablelist>
    </sect1>

diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml
index 4b535809b6..b3faec97e4 100644
--- a/doc/src/sgml/maintenance.sgml
+++ b/doc/src/sgml/maintenance.sgml
@@ -818,10 +818,17 @@ analyze threshold = analyze base threshold + analyze scale factor * number of tu
     is compared to the total number of tuples inserted, updated, or deleted
     since the last <command>ANALYZE</command>.
     For partitioned tables, inserts, updates and deletes on partitions
-    are counted towards this threshold; however, DDL
-    operations such as <literal>ATTACH</literal>, <literal>DETACH</literal>
-    and <literal>DROP</literal> are not, so running a manual
-    <command>ANALYZE</command> is recommended if the partition added or
+    are counted towards this threshold.
+    In the case of DDL operations such as
+    <literal>ATTACH</literal>, <literal>DETACH</literal> and <literal>DROP</literal>,
+    the number of tuples of partitions is counted instead.  They are controled
+    by <xref linkend="guc-autovacuum-analyze-attach-partition"/>,
+    <xref linkend="guc-autovacuum-analyze-detach-partition"/> and
+    <xref linkend="guc-autovacuum-analyze-drop-partition"/>, respectively.
+    The default values are on; but when <varname>autovacuum_analyze_attach_partition</varname>,
+    <varname>autovacuum_analyze_detach_partition</varname> and
+    <varname>autovacuum_analyze_drop_partition</varname> are set to off,
+    running a manual <command>ANALYZE</command> is recommended if the partition added or
     removed contains a statistically significant volume of data.
    </para>

diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml
index c6d0a35e50..ad2aa2f8b9 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -1733,6 +1733,48 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
     </listitem>
    </varlistentry>

+   <varlistentry id="reloption-autovacuum-analyze-attach-partition" xreflabel="autovacuum_analyze_attach_partition">
+    <term><literal>autovacuum_analyze_attach_partition</literal> (<type>boolean</type>)
+    <indexterm>
+     <primary><varname>autovacuum_analyze_attach_partition</varname> storage parameter</primary>
+    </indexterm>
+    </term>
+    <listitem>
+     <para>
+      Per-table value
+      for <xref linkend="guc-autovacuum-analyze-attach-partition"/> parameter.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry id="reloption-autovacuum-analyze-detach-partition" xreflabel="autovacuum_analyze_detach_partition">
+    <term><literal>autovacuum_analyze_detach_partition</literal> (<type>boolean</type>)
+    <indexterm>
+     <primary><varname>autovacuum_analyze_detach_partition</varname> storage parameter</primary>
+    </indexterm>
+    </term>
+    <listitem>
+     <para>
+      Per-table value
+      for <xref linkend="guc-autovacuum-analyze-detach-partition"/> parameter.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry id="reloption-autovacuum-analyze-drop-partition" xreflabel="autovacuum_analyze_drop_partition">
+    <term><literal>autovacuum_analyze_drop_partition</literal> (<type>boolean</type>)
+    <indexterm>
+     <primary><varname>autovacuum_analyze_drop_partition</varname> storage parameter</primary>
+    </indexterm>
+    </term>
+    <listitem>
+     <para>
+      Per-table value
+      for <xref linkend="guc-autovacuum-analyze-drop-partition"/> parameter.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry id="reloption-log-autovacuum-min-duration" xreflabel="log_autovacuum_min_duration">
     <term><literal>log_autovacuum_min_duration</literal>, <literal>toast.log_autovacuum_min_duration</literal> (<type>integer</type>)
     <indexterm>
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 5554275e64..45ad2b882e 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -160,6 +160,33 @@ static relopt_bool boolRelOpts[] =
 	},
 	{
 		{
+			"autovacuum_analyze_attach_partition",
+			"Count ATTACH PARTITION commands as row updates",
+			RELOPT_KIND_PARTITIONED,
+			AccessExclusiveLock
+		},
+		true
+	},
+	{
+		{
+			"autovacuum_analyze_detach_partition",
+			"Count DETACH PARTITION commands as row updates",
+			RELOPT_KIND_PARTITIONED,
+			AccessExclusiveLock
+		},
+		true
+	},
+	{
+		{
+			"autovacuum_analyze_drop_partition",
+			"Counts DROP TABLE commands executed on partitions as row updates",
+			RELOPT_KIND_PARTITIONED,
+			AccessExclusiveLock
+		},
+		true
+	},
+	{
+		{
 			"deduplicate_items",
 			"Enables \"deduplicate items\" feature for this btree index",
 			RELOPT_KIND_BTREE,
@@ -1852,6 +1879,12 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
 		offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_scale_factor)},
 		{"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
 		offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_scale_factor)},
+		{"autovacuum_analyze_attach_partition", RELOPT_TYPE_BOOL,
+		 offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_attach_partition)},
+		{"autovacuum_analyze_detach_partition", RELOPT_TYPE_BOOL,
+		 offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_detach_partition)},
+		{"autovacuum_analyze_drop_partition", RELOPT_TYPE_BOOL,
+		 offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_drop_partition)},
 		{"user_catalog_table", RELOPT_TYPE_BOOL,
 		offsetof(StdRdOptions, user_catalog_table)},
 		{"parallel_workers", RELOPT_TYPE_INT,
@@ -1962,8 +1995,10 @@ bytea *
 partitioned_table_reloptions(Datum reloptions, bool validate)
 {
 	/*
-	 * autovacuum_enabled, autovacuum_analyze_threshold and
-	 * autovacuum_analyze_scale_factor are supported for partitioned tables.
+	 * autovacuum_enabled, autovacuum_analyze_threshold,
+	 * autovacuum_analyze_scale_factor, autovacuum_analyze_attach_partition,
+	 * autovacuum_analyze_detach_partition and autovacuum_analyze_drop_partition
+	 * are supported for partitioned tables.
 	 */

 	return default_reloptions(reloptions, validate, RELOPT_KIND_PARTITIONED);
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 1293dc04ca..3d89783f99 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -74,6 +74,7 @@
 #include "parser/parse_relation.h"
 #include "parser/parsetree.h"
 #include "partitioning/partdesc.h"
+#include "pgstat.h"
 #include "storage/lmgr.h"
 #include "storage/predicate.h"
 #include "storage/smgr.h"
@@ -2028,6 +2029,11 @@ heap_drop_with_catalog(Oid relid)
 	RelationForgetRelation(relid);

 	/*
+	 * update changes_since_analyze of its ancestors for auto ANALYZE
+	 */
+	pgstat_report_anl_ancestors(relid, false, false, true);
+
+	/*
 	 * remove inheritance information
 	 */
 	RelationRemoveInheritance(relid);
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 426c1e6710..f49498c495 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -694,7 +694,7 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
 		onerel->rd_rel->relkind == RELKIND_RELATION &&
 		onerel->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT)
 	{
-		pgstat_report_anl_ancestors(RelationGetRelid(onerel));
+		pgstat_report_anl_ancestors(RelationGetRelid(onerel), false, false, false);
 	}

 	/*
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 4e23c7fce5..37a7b43383 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -17312,6 +17312,9 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd,

 	ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachrel));

+	/* update changes_since_analyze of its ancestors for auto ANALYZE */
+	pgstat_report_anl_ancestors(RelationGetRelid(attachrel), true, false, false);
+
 	/* keep our lock until commit */
 	table_close(attachrel, NoLock);

@@ -17859,6 +17862,9 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent,
 		RemoveInheritance(partRel, rel, true);
 	}

+	/* update changes_since_analyze of its ancestors for auto ANALYZE */
+	pgstat_report_anl_ancestors(RelationGetRelid(partRel), false, true, false);
+
 	/* Drop any triggers that were cloned on creation/attach. */
 	DropClonedTriggersFromPartition(RelationGetRelid(partRel));

diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index d516df0ac5..dd7455f787 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -128,6 +128,10 @@ int			autovacuum_multixact_freeze_max_age;
 double		autovacuum_vac_cost_delay;
 int			autovacuum_vac_cost_limit;

+bool		autovacuum_anl_attach_partition = false;
+bool		autovacuum_anl_detach_partition = false;
+bool		autovacuum_anl_drop_partition = false;
+
 int			Log_autovacuum_min_duration = -1;

 /* how long to keep pgstat data in the launcher, in milliseconds */
@@ -2100,7 +2104,7 @@ do_autovacuum(void)
 			tabentry->changes_since_analyze -
 			tabentry->changes_since_analyze_reported > 0)
 		{
-			pgstat_report_anl_ancestors(relid);
+			pgstat_report_anl_ancestors(relid, false, false, false);
 			updated = true;
 		}
 	}
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index b0d07c0e0b..bd469dbcfc 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -1667,11 +1667,15 @@ pgstat_report_analyze(Relation rel,
  *
  *	Send list of partitioned table ancestors of the given partition to the
  *	collector.  The collector is in charge of propagating the analyze tuple
- *	counts from the partition to its ancestors.  This is necessary so that
- *	other processes can decide whether to analyze the partitioned tables.
+ *	counts from the partition to its ancestors.  The attached, detached
+ *	and dropped flags indicate whether this fuction is called by ATTACH/DETACH
+ *	PARTITION and DROP TABLE command, respectively.  If either flag is TRUE,
+ *	the collector will propagate the partition's livetuples to its ancestors'
+ *	analyze tuple counts.  This is necessary so that other processes can
+ *	decide whether to analyze the partitioned tables.
  */
 void
-pgstat_report_anl_ancestors(Oid relid)
+pgstat_report_anl_ancestors(Oid relid, bool attached, bool detached, bool dropped)
 {
 	PgStat_MsgAnlAncestors msg;
 	List	   *ancestors;
@@ -1680,12 +1684,33 @@ pgstat_report_anl_ancestors(Oid relid)
 	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_ANL_ANCESTORS);
 	msg.m_databaseid = MyDatabaseId;
 	msg.m_tableoid = relid;
+	msg.m_count_livetuples = (attached || detached || dropped) ? true : false;
+	msg.m_reset_reportedcounter = detached;
 	msg.m_nancestors = 0;

 	ancestors = get_partition_ancestors(relid);
 	foreach(lc, ancestors)
 	{
 		Oid			ancestor = lfirst_oid(lc);
+		Relation	ancestorRel;
+		AutoVacOpts *avopts;
+
+		ancestorRel = table_open(ancestor, AccessShareLock);
+		avopts = ancestorRel->rd_options
+			? &(((StdRdOptions *) ancestorRel->rd_options)->autovacuum)
+			: NULL;
+
+		/* Check reloptions */
+		if ((attached && (avopts ? !avopts->analyze_attach_partition
+								 : !autovacuum_anl_attach_partition)) ||
+			(detached && (avopts ? !avopts->analyze_detach_partition
+								 : !autovacuum_anl_detach_partition)) ||
+			(dropped && (avopts ? !avopts->analyze_drop_partition
+							   : !autovacuum_anl_drop_partition)))
+		{
+			table_close(ancestorRel, AccessShareLock);
+			continue;
+		}

 		msg.m_ancestors[msg.m_nancestors] = ancestor;
 		if (++msg.m_nancestors >= PGSTAT_NUM_ANCESTORENTRIES)
@@ -1694,6 +1719,8 @@ pgstat_report_anl_ancestors(Oid relid)
 						msg.m_nancestors * sizeof(Oid));
 			msg.m_nancestors = 0;
 		}
+
+		table_close(ancestorRel, AccessShareLock);
 	}

 	if (msg.m_nancestors > 0)
@@ -5301,12 +5328,20 @@ pgstat_recv_anl_ancestors(PgStat_MsgAnlAncestors *msg, int len)
 		PgStat_StatTabEntry *ancestor;

 		ancestor = pgstat_get_tab_entry(dbentry, ancestor_relid, true);
-		ancestor->changes_since_analyze +=
-			tabentry->changes_since_analyze - tabentry->changes_since_analyze_reported;
-	}

-	tabentry->changes_since_analyze_reported = tabentry->changes_since_analyze;
+		if (msg->m_count_livetuples)
+			ancestor->changes_since_analyze +=
+				tabentry->n_live_tuples - tabentry->changes_since_analyze_reported;
+		else
+			ancestor->changes_since_analyze +=
+				tabentry->changes_since_analyze - tabentry->changes_since_analyze_reported;
+	}

+	/* Reset changes_since_analyze_reported to zero if the partition is detached */
+	if (msg->m_reset_reportedcounter)
+		tabentry->changes_since_analyze_reported = 0;
+	else
+		tabentry->changes_since_analyze_reported = tabentry->changes_since_analyze;
 }

 /* ----------
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 68b62d523d..f2068e22d3 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -1569,7 +1569,33 @@ static struct config_bool ConfigureNamesBool[] =
 		true,
 		NULL, NULL, NULL
 	},
-
+	{
+		{"autovacuum_analyze_attach_partition", PGC_SIGHUP, AUTOVACUUM,
+			gettext_noop("Count ATTACH PARTITION commands as row updates."),
+			NULL,
+		},
+		&autovacuum_anl_attach_partition,
+		true,
+		NULL, NULL, NULL
+	},
+	{
+		{"autovacuum_analyze_detach_partition", PGC_SIGHUP, AUTOVACUUM,
+			gettext_noop("Count DETACH PARTITION commands as row updates."),
+			NULL,
+		},
+		&autovacuum_anl_detach_partition,
+		true,
+		NULL, NULL, NULL
+	},
+	{
+		{"autovacuum_analyze_drop_partition", PGC_SIGHUP, AUTOVACUUM,
+			gettext_noop("Count DROP TABLE commands executed on partitions as row updates."),
+			NULL,
+		},
+		&autovacuum_anl_drop_partition,
+		true,
+		NULL, NULL, NULL
+	},
 	{
 		{"trace_notify", PGC_USERSET, DEVELOPER_OPTIONS,
 			gettext_noop("Generates debugging output for LISTEN and NOTIFY."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index ddbb6dc2be..4b603af5f9 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -643,6 +643,12 @@
 #autovacuum_vacuum_cost_limit = -1	# default vacuum cost limit for
 					# autovacuum, -1 means use
 					# vacuum_cost_limit
+#autovacuum_analyze_attach_partition = on	# count ATTACH PARTITION commands
+						# as row updates
+#autovacuum_analyze_detach_partition = on	# count DETACH PARTITION commands
+						# as row updates
+#autovacuum_analyze_drop_partition = on		# count DROP TABLE commands executed
+						# on partitions as row updates


 #------------------------------------------------------------------------------
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index bd8e9ea2f8..7f6a5b933b 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -1099,6 +1099,9 @@ static const pgsql_thing_t words_after_create[] = {

 /* Storage parameters for CREATE TABLE and ALTER TABLE */
 static const char *const table_storage_parameters[] = {
+	"autovacuum_analyze_attach_partition",
+	"autovacuum_analyze_detach_partition",
+	"autovacuum_analyze_drop_partition",
 	"autovacuum_analyze_scale_factor",
 	"autovacuum_analyze_threshold",
 	"autovacuum_enabled",
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 9612c0a6c2..644fb40d85 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -438,7 +438,7 @@ typedef struct PgStat_MsgAnalyze
  * ----------
  */
 #define PGSTAT_NUM_ANCESTORENTRIES    \
-	((PGSTAT_MSG_PAYLOAD - sizeof(Oid) - sizeof(Oid) - sizeof(int))	\
+	((PGSTAT_MSG_PAYLOAD - 2 * sizeof(Oid) - 2 * sizeof(bool) - sizeof(int))  \
 	 / sizeof(Oid))

 typedef struct PgStat_MsgAnlAncestors
@@ -446,6 +446,8 @@ typedef struct PgStat_MsgAnlAncestors
 	PgStat_MsgHdr m_hdr;
 	Oid			m_databaseid;
 	Oid			m_tableoid;
+	bool		m_count_livetuples;
+	bool		m_reset_reportedcounter;
 	int			m_nancestors;
 	Oid			m_ancestors[PGSTAT_NUM_ANCESTORENTRIES];
 } PgStat_MsgAnlAncestors;
@@ -1002,7 +1004,8 @@ extern void pgstat_report_vacuum(Oid tableoid, bool shared,
 extern void pgstat_report_analyze(Relation rel,
 								  PgStat_Counter livetuples, PgStat_Counter deadtuples,
 								  bool resetcounter);
-extern void pgstat_report_anl_ancestors(Oid relid);
+extern void pgstat_report_anl_ancestors(Oid relid,
+										bool attached, bool detached, bool dropped);

 extern void pgstat_report_recovery_conflict(int reason);
 extern void pgstat_report_deadlock(void);
diff --git a/src/include/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h
index aacdd0f575..2cbb53d1b3 100644
--- a/src/include/postmaster/autovacuum.h
+++ b/src/include/postmaster/autovacuum.h
@@ -41,6 +41,9 @@ extern int	autovacuum_freeze_max_age;
 extern int	autovacuum_multixact_freeze_max_age;
 extern double autovacuum_vac_cost_delay;
 extern int	autovacuum_vac_cost_limit;
+extern bool	autovacuum_anl_attach_partition;
+extern bool	autovacuum_anl_detach_partition;
+extern bool	autovacuum_anl_drop_partition;

 /* autovacuum launcher PID, only valid when worker is shutting down */
 extern int	AutovacuumLauncherPid;
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 774ac5b2b1..e479bd3f87 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -305,6 +305,9 @@ typedef struct AutoVacOpts
 	float8		vacuum_scale_factor;
 	float8		vacuum_ins_scale_factor;
 	float8		analyze_scale_factor;
+	bool		analyze_attach_partition;
+	bool		analyze_detach_partition;
+	bool		analyze_drop_partition;
 } AutoVacOpts;

 typedef struct StdRdOptions
