diff --git a/docs/en/sql-reference/statements/grant.md b/docs/en/sql-reference/statements/grant.md
index e6073f3523a..6106ff88de8 100644
--- a/docs/en/sql-reference/statements/grant.md
+++ b/docs/en/sql-reference/statements/grant.md
@@ -201,6 +201,7 @@ Hierarchy of privileges:
- `S3`
- [dictGet](#grant-dictget)
- [displaySecretsInShowAndSelect](#grant-display-secrets)
+- [TABLE ENGINE](#grant-table-engine)
Examples of how this hierarchy is treated:
@@ -495,6 +496,15 @@ and
[`format_display_secrets_in_show_and_select` format setting](../../operations/settings/formats#format_display_secrets_in_show_and_select)
are turned on.
+### TABLE ENGINE
+
+Allows using a specified table engine when creating a table. Applies to [table engines](../../engines/table-engines/index.md).
+
+**Examples**
+
+- `GRANT TABLE ENGINE ON * TO john`
+- `GRANT TABLE ENGINE ON TinyLog TO john`
+
### ALL
Grants all the privileges on regulated entity to a user account or a role.
diff --git a/programs/server/config.xml b/programs/server/config.xml
index 6a40818332b..cb7fba90c52 100644
--- a/programs/server/config.xml
+++ b/programs/server/config.xml
@@ -742,6 +742,10 @@
It also enables 'changeable_in_readonly' constraint type -->
true
+
+ false
+
600
diff --git a/src/Access/AccessControl.cpp b/src/Access/AccessControl.cpp
index d02af01126a..da047d1cb1d 100644
--- a/src/Access/AccessControl.cpp
+++ b/src/Access/AccessControl.cpp
@@ -285,6 +285,7 @@ void AccessControl::setUpFromMainConfig(const Poco::Util::AbstractConfiguration
setSelectFromSystemDatabaseRequiresGrant(config_.getBool("access_control_improvements.select_from_system_db_requires_grant", false));
setSelectFromInformationSchemaRequiresGrant(config_.getBool("access_control_improvements.select_from_information_schema_requires_grant", false));
setSettingsConstraintsReplacePrevious(config_.getBool("access_control_improvements.settings_constraints_replace_previous", false));
+ setTableEnginesRequireGrant(config_.getBool("access_control_improvements.table_engines_require_grant", false));
addStoragesFromMainConfig(config_, config_path_, get_zookeeper_function_);
diff --git a/src/Access/AccessControl.h b/src/Access/AccessControl.h
index 904f77faf90..60b6d49cd1f 100644
--- a/src/Access/AccessControl.h
+++ b/src/Access/AccessControl.h
@@ -182,6 +182,9 @@ public:
void setSettingsConstraintsReplacePrevious(bool enable) { settings_constraints_replace_previous = enable; }
bool doesSettingsConstraintsReplacePrevious() const { return settings_constraints_replace_previous; }
+ void setTableEnginesRequireGrant(bool enable) { table_engines_require_grant = enable; }
+ bool doesTableEnginesRequireGrant() const { return table_engines_require_grant; }
+
std::shared_ptr getContextAccess(const ContextAccessParams & params) const;
std::shared_ptr getEnabledRoles(
@@ -258,6 +261,7 @@ private:
std::atomic_bool select_from_system_db_requires_grant = false;
std::atomic_bool select_from_information_schema_requires_grant = false;
std::atomic_bool settings_constraints_replace_previous = false;
+ std::atomic_bool table_engines_require_grant = false;
std::atomic_int bcrypt_workfactor = 12;
std::atomic default_password_type = AuthenticationType::SHA256_PASSWORD;
};
diff --git a/src/Access/Common/AccessType.h b/src/Access/Common/AccessType.h
index 222284480a0..93c5bd13030 100644
--- a/src/Access/Common/AccessType.h
+++ b/src/Access/Common/AccessType.h
@@ -12,7 +12,7 @@ enum class AccessType
/// Macro M should be defined as M(name, aliases, node_type, parent_group_name)
/// where name is identifier with underscores (instead of spaces);
/// aliases is a string containing comma-separated list;
-/// node_type either specifies access type's level (GLOBAL/NAMED_COLLECTION/DATABASE/TABLE/DICTIONARY/VIEW/COLUMNS),
+/// node_type either specifies access type's level (GLOBAL/NAMED_COLLECTION/TABLE_ENGINE/DATABASE/TABLE/DICTIONARY/VIEW/COLUMNS),
/// or specifies that the access type is a GROUP of other access types;
/// parent_group_name is the name of the group containing this access type (or NONE if there is no such group).
/// NOTE A parent group must be declared AFTER all its children.
diff --git a/src/Access/ContextAccess.cpp b/src/Access/ContextAccess.cpp
index 0943e797e3f..3de431a8f8c 100644
--- a/src/Access/ContextAccess.cpp
+++ b/src/Access/ContextAccess.cpp
@@ -547,6 +547,9 @@ bool ContextAccess::checkAccessImplHelper(AccessFlags flags, const Args &... arg
if (flags & AccessType::CLUSTER && !access_control->doesOnClusterQueriesRequireClusterGrant())
flags &= ~AccessType::CLUSTER;
+ if (flags & AccessType::TABLE_ENGINE && !access_control->doesTableEnginesRequireGrant())
+ flags &= ~AccessType::TABLE_ENGINE;
+
if (!flags)
return true;