When you run GRANT with ON CLUSTER, every server in the cluster will crash.

Version 22.6.2.12. 

I used the official docker image to create a small cluster. You can see the config here and try it out with docker-compose: https://github.com/maybedino/test-clickhouse

Then log in with the default user and try to add another user:

```sql
create user testuser on cluster testcluster identified with sha256_password by 'test'
```

```sql
grant on cluster testcluster all on *.* to testuser with grant option
```

GRANT will crash every server in the cluster:

```
2022.06.30 08:18:38.865561 [ 273 ] {} <Fatal> BaseDaemon: ########################################
2022.06.30 08:18:38.865712 [ 273 ] {} <Fatal> BaseDaemon: (version 22.6.2.12 (official build), build id: 52AFD84A0FEDD1BA) (from thread 262) (query_id: 6469e16f-b37f-4565-a9f7-e8e023c1632e) (query: /* ddl_entry=query-0000000001 */ GRANT ALL ON *.* TO testuser WITH GRANT OPTION) Received signal Segmentation fault (11)
2022.06.30 08:18:38.865769 [ 273 ] {} <Fatal> BaseDaemon: Address: 0x16b Access: read. Address not mapped to object.
2022.06.30 08:18:38.865809 [ 273 ] {} <Fatal> BaseDaemon: Stack trace: 0x1541b8dd 0x1659fa4b 0x16566556 0x1656a5c4 0x15cdcb49 0x15cdb557 0x15cd94d3 0x15cd3405 0x15ce6ff6 0xb94d077 0xb95049d 0x7f0096c6a609 0x7f0096b8f133
2022.06.30 08:18:38.865902 [ 273 ] {} <Fatal> BaseDaemon: 2. bool DB::ContextAccess::checkAccessImplHelper<true, true>(DB::AccessFlags) const @ 0x1541b8dd in /usr/bin/clickhouse
2022.06.30 08:18:38.866029 [ 273 ] {} <Fatal> BaseDaemon: 3. DB::InterpreterGrantQuery::execute() @ 0x1659fa4b in /usr/bin/clickhouse
2022.06.30 08:18:38.866053 [ 273 ] {} <Fatal> BaseDaemon: 4. ? @ 0x16566556 in /usr/bin/clickhouse
2022.06.30 08:18:38.866088 [ 273 ] {} <Fatal> BaseDaemon: 5. DB::executeQuery(DB::ReadBuffer&, DB::WriteBuffer&, bool, std::__1::shared_ptr<DB::Context>, std::__1::function<void (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)>, std::__1::optional<DB::FormatSettings> const&) @ 0x1656a5c4 in /usr/bin/clickhouse
2022.06.30 08:18:38.866120 [ 273 ] {} <Fatal> BaseDaemon: 6. DB::DDLWorker::tryExecuteQuery(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, DB::DDLTaskBase&, std::__1::shared_ptr<zkutil::ZooKeeper> const&) @ 0x15cdcb49 in /usr/bin/clickhouse
2022.06.30 08:18:38.866140 [ 273 ] {} <Fatal> BaseDaemon: 7. DB::DDLWorker::processTask(DB::DDLTaskBase&, std::__1::shared_ptr<zkutil::ZooKeeper> const&) @ 0x15cdb557 in /usr/bin/clickhouse
2022.06.30 08:18:38.866155 [ 273 ] {} <Fatal> BaseDaemon: 8. DB::DDLWorker::scheduleTasks(bool) @ 0x15cd94d3 in /usr/bin/clickhouse
2022.06.30 08:18:38.866170 [ 273 ] {} <Fatal> BaseDaemon: 9. DB::DDLWorker::runMainThread() @ 0x15cd3405 in /usr/bin/clickhouse
2022.06.30 08:18:38.866190 [ 273 ] {} <Fatal> BaseDaemon: 10. ThreadFromGlobalPool::ThreadFromGlobalPool<void (DB::DDLWorker::*)(), DB::DDLWorker*>(void (DB::DDLWorker::*&&)(), DB::DDLWorker*&&)::'lambda'()::operator()() @ 0x15ce6ff6 in /usr/bin/clickhouse
2022.06.30 08:18:38.866209 [ 273 ] {} <Fatal> BaseDaemon: 11. ThreadPoolImpl<std::__1::thread>::worker(std::__1::__list_iterator<std::__1::thread, void*>) @ 0xb94d077 in /usr/bin/clickhouse
2022.06.30 08:18:38.866223 [ 273 ] {} <Fatal> BaseDaemon: 12. ? @ 0xb95049d in /usr/bin/clickhouse
2022.06.30 08:18:38.866245 [ 273 ] {} <Fatal> BaseDaemon: 13. ? @ 0x7f0096c6a609 in ?
2022.06.30 08:18:38.866259 [ 273 ] {} <Fatal> BaseDaemon: 14. clone @ 0x7f0096b8f133 in ?
2022.06.30 08:18:38.993700 [ 273 ] {} <Fatal> BaseDaemon: Integrity check of the executable successfully passed (checksum: 894C4AAB85FCB9AAC26136BC446CC5AF)
/entrypoint.sh: line 155:    43 Segmentation fault      (core dumped) /usr/bin/clickhouse su "${USER}:${GROUP}" /usr/bin/clickhouse-server --config-file="$CLICKHOUSE_CONFIG" "$@"
```

And then you can't start the cluster anymore because it stays in the task queue and keeps crashing the server. You need to manually stop the server and remove the tasks from clickhouse-keeper. (Or just delete the volumes in this test cluster.)

The same thing happens with REVOKE ... ON CLUSTER ....

Running GRANT without ON CLUSTER on every server individually works fine.

I ran it once with crash reports enabled, not sure if it worked.

{
    return checkAdminOptionImplHelper<throw_if_denied>(to_array(role_id), [&names_of_roles](const UUID & id, size_t) { auto it = names_of_roles.find(id); return (it != names_of_roles.end()) ? it->second : std::optional<String>{}; });
}
template <bool throw_if_denied>
bool ContextAccess::checkAdminOptionImpl(const std::vector<UUID> & role_ids) const
{
    return checkAdminOptionImplHelper<throw_if_denied>(role_ids, [this](const UUID & id, size_t) { return access_control->tryReadName(id); });
}
template <bool throw_if_denied>
bool ContextAccess::checkAdminOptionImpl(const std::vector<UUID> & role_ids, const Strings & names_of_roles) const
{
    return checkAdminOptionImplHelper<throw_if_denied>(role_ids, [&names_of_roles](const UUID &, size_t i) { return std::optional<String>{names_of_roles[i]}; });
}
template <bool throw_if_denied>
bool ContextAccess::checkAdminOptionImpl(const std::vector<UUID> & role_ids, const std::unordered_map<UUID, String> & names_of_roles) const
{
    return checkAdminOptionImplHelper<throw_if_denied>(role_ids, [&names_of_roles](const UUID & id, size_t) { auto it = names_of_roles.find(id); return (it != names_of_roles.end()) ? it->second : std::optional<String>{}; });
}
bool ContextAccess::hasAdminOption(const UUID & role_id) const { return checkAdminOptionImpl<false>(role_id); }
bool ContextAccess::hasAdminOption(const UUID & role_id, const String & role_name) const { return checkAdminOptionImpl<false>(role_id, role_name); }
bool ContextAccess::hasAdminOption(const UUID & role_id, const std::unordered_map<UUID, String> & names_of_roles) const { return checkAdminOptionImpl<false>(role_id, names_of_roles); }
bool ContextAccess::hasAdminOption(const std::vector<UUID> & role_ids) const { return checkAdminOptionImpl<false>(role_ids); }
bool ContextAccess::hasAdminOption(const std::vector<UUID> & role_ids, const Strings & names_of_roles) const { return checkAdminOptionImpl<false>(role_ids, names_of_roles); }
bool ContextAccess::hasAdminOption(const std::vector<UUID> & role_ids, const std::unordered_map<UUID, String> & names_of_roles) const { return checkAdminOptionImpl<false>(role_ids, names_of_roles); }
void ContextAccess::checkAdminOption(const UUID & role_id) const { checkAdminOptionImpl<true>(role_id); }
void ContextAccess::checkAdminOption(const UUID & role_id, const String & role_name) const { checkAdminOptionImpl<true>(role_id, role_name); }