The following integration test describes the issue more than enough. The test starts 3 nodes to cover all possible cases.

* _root -> leaf_
* old server -> new server
* new server -> old server
* new server -> new server

git bisecting leads to https://github.com/ClickHouse/ClickHouse/commit/64ea1f82989ad45555629759b6f395804b12c864

<details>
<pre>
git bisect start
# good: [5bdc57004682a5e0236ec630546d20ad752c2fde] Improve performance of GROUP BY multiple fixed size keys
git bisect good 5bdc57004682a5e0236ec630546d20ad752c2fde
# bad: [545528917fd7700be0f6c582be970dbd23feeab5] Fix tests.
git bisect bad 545528917fd7700be0f6c582be970dbd23feeab5
# good: [74a07e406b7199dc5aa7804f5e5c63f6477118de] Even more stable
git bisect good 74a07e406b7199dc5aa7804f5e5c63f6477118de
# good: [c8da611fcd5c454431b49a407df36fa4ff745b9b] Merge pull request #21023 from ClickHouse/fix-datetime64-formatting
git bisect good c8da611fcd5c454431b49a407df36fa4ff745b9b
# good: [6dc683dce6af72239793906c633832de2386448e] Merge pull request #19815 from otrazhenia/evgsudarikova-DOCSUP-6149
git bisect good 6dc683dce6af72239793906c633832de2386448e
# good: [8f81dce32f6eebf448bd8a65ad4192ac746cc66f] Merge pull request #20585 from ClickHouse/persistent_nukeeper_log_storage
git bisect good 8f81dce32f6eebf448bd8a65ad4192ac746cc66f
# good: [3feded8d0cb562b7d0ed7a8c4bd4939f2524301c] Create type-conversion-functions.md
git bisect good 3feded8d0cb562b7d0ed7a8c4bd4939f2524301c
# good: [3cda69feaf1295333a1dc2f4030730bd3edbb425] Merge pull request #20632 from ClickHouse/akz/mysqlxx-randomize-replicas
git bisect good 3cda69feaf1295333a1dc2f4030730bd3edbb425
# good: [994b998df9863e772b438a858a2cdabdb2ce27ea] Update docs/ru/sql-reference/operators/in.md
git bisect good 994b998df9863e772b438a858a2cdabdb2ce27ea
# good: [802e5e725b744fe608e55aaa6456ea3e8989fe83] Merge pull request #19965 from ka1bi4/romanzhukov-DOCSUP-5822-update-accurateCastOrNull
git bisect good 802e5e725b744fe608e55aaa6456ea3e8989fe83
# bad: [2bf533630c7a70232b1615e74cca9d8c699c7de0] Fix tests.
git bisect bad 2bf533630c7a70232b1615e74cca9d8c699c7de0
# bad: [64ea1f82989ad45555629759b6f395804b12c864] Save packet keys.
git bisect bad 64ea1f82989ad45555629759b6f395804b12c864
# first bad commit: [64ea1f82989ad45555629759b6f395804b12c864] Save packet keys.
</pre>
</details>

I tried to simplify the test, but even minor changes to the test make it pass again. 

```py
import pytest

from helpers.cluster import ClickHouseCluster

cluster = ClickHouseCluster(__file__)
node1 = cluster.add_instance('node1', with_zookeeper=True, image='yandex/clickhouse-server', tag='20.8', with_installed_binary=True)
node2 = cluster.add_instance('node2', with_zookeeper=True, image='yandex/clickhouse-server')
node3 = cluster.add_instance('node3', with_zookeeper=True, image='yandex/clickhouse-server')


@pytest.fixture(scope="module")
def start_cluster():
    try:
        cluster.start()
        yield cluster

    finally:
        cluster.shutdown()


def test_two_level_merge(start_cluster):
    for node in start_cluster.instances.values():
        node.query(
            """
            CREATE TABLE IF NOT EXISTS test_two_level_merge(date Date, zone UInt32, number UInt32)
            ENGINE = MergeTree() PARTITION BY toUInt64(number / 1000) ORDER BY tuple();

            INSERT INTO
                test_two_level_merge
            SELECT
                toDate('2021-09-28') - number / 1000,
                249081628,
                number
            FROM
                numbers(15000);
            """
        )

    # covers only the keys64 method
    for node in start_cluster.instances.values():
        print(node.query(
            """
            SELECT
                throwIf(uniqExact(date) != count(), 'group by is borked')
            FROM (
                SELECT
                    date
                FROM
                    remote('node{1,2}', default.test_two_level_merge)
                WHERE
                    date BETWEEN toDate('2021-09-20') AND toDate('2021-09-28')
                    AND zone = 249081628
                GROUP by date, zone
            )
            SETTINGS
                group_by_two_level_threshold = 1,
                group_by_two_level_threshold_bytes = 1,
                max_threads = 2,
                prefer_localhost_replica = 0
            """
        ))
```

cc @KochetovNicolai 

One considered fix is to just bump `DBMS_MIN_REVISION_WITH_CURRENT_AGGREGATION_VARIANT_SELECTION_METHOD` and also handle in in TCPHandler. This will introduce some performance degradation during upgrade.
sendLogs();
            sendEndOfStream();
            
            
            
            state.reset();
            query_scope.reset();
        }
        catch (const Exception & e)
        {
            state.io.onException();
            exception.emplace(e);
            if (e.code() == ErrorCodes::UNKNOWN_PACKET_FROM_CLIENT)
                throw;
            
            
            
            if (e.code() == ErrorCodes::UNEXPECTED_PACKET_FROM_CLIENT)
                network_error = true;
            
            if (e.code() == ErrorCodes::SOCKET_TIMEOUT)
                network_error = true;
        }
        catch (const Poco::Net::NetException & e)
        {
            /** We can get here if there was an error during connection to the client,
             *  or in connection with a remote server that was used to process the request.
             *  It is not possible to distinguish between these two cases.
             *  Although in one of them, we have to send exception to the client, but in the other - we can not.
             *  We will try to send exception to the client in any case - see below.