diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 6d34c319888df7f47bf3e39f65e0383d6f21f0b5..6a0fabc978de96dab22381c24e9fcbe7b0e0f187 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -186,17 +186,19 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     <term><literal>FREEZE</literal></term>
     <listitem>
      <para>
-      Specifies copying the data with rows already frozen, just as they
+      Requests copying the data with rows already frozen, just as they
       would be after running the <command>VACUUM FREEZE</> command.
       This is intended as a performance option for initial data loading.
       Rows will be frozen only if the table being loaded has been created
       in the current subtransaction, there are no cursors open and there
       are no older snapshots held by this transaction. If those conditions
       are not met the command will continue without error though will not
-      freeze rows.
+      freeze rows. It is also possible in rare cases that the request
+      cannot be honoured for internal reasons, hence <literal>FREEZE</literal>
+      is more of a guideline than a hard rule.
      </para>
      <para>
-      Note that all sessions will immediately be able to see the data
+      Note that all other sessions will immediately be able to see the data
       once it has been successfully loaded. This violates the normal rules
       of MVCC visibility and by specifying this option the user acknowledges
       explicitly that this is understood.
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 09f40667f68281cef6fecf6cde89aea1daf73771..c4104e4d9d52115034ede98ca9edb6664f56bee8 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -1993,6 +1993,11 @@ CopyFrom(CopyState cstate)
 		 * after xact cleanup. Note that the stronger test of exactly
 		 * which subtransaction created it is crucial for correctness
 		 * of this optimisation.
+		 *
+		 * Note that because the test is unreliable in case of relcache reset
+		 * we cannot guarantee that we can honour the request to FREEZE.
+		 * If we cannot honour the request we do so silently, firstly to
+		 * avoid noise for the user and also to avoid obscure test failures.
 		 */
 		if (cstate->freeze &&
 			ThereAreNoPriorRegisteredSnapshots() &&
@@ -2001,11 +2006,6 @@ CopyFrom(CopyState cstate)
 			hi_options |= HEAP_INSERT_FROZEN;
 	}
 
-	if (cstate->freeze && (hi_options & HEAP_INSERT_FROZEN) == 0)
-		ereport(NOTICE,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("FREEZE option specified but pre-conditions not met")));
-
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
 	 * index-entry-making machinery.  (There used to be a huge amount of code