diff --git a/test/int/test_access_control.py b/test/int/test_access_control.py
new file mode 100644
index 0000000000000000000000000000000000000000..40295220ac6d99006daecbfc875f26842ac0148a
--- /dev/null
+++ b/test/int/test_access_control.py
@@ -0,0 +1,150 @@
+import pytest
+from typing import TypedDict
+
+from conftest import (
+    Cluster,
+    ReturnError,
+)
+
+
+class AsUser(TypedDict):
+    user: str
+    password: str
+
+
+as_alice: AsUser = {
+    "user": "alice",
+    "password": "topsecret",
+}
+
+as_bob: AsUser = {
+    "user": "bob",
+    "password": "totallysecret",
+}
+
+_3_SEC = 3
+as_alice = dict(user="alice", password="topsecret")
+as_bob = dict(user="bob", password="totallysecret")
+
+
+def test_access_global_table(cluster: Cluster):
+    (i1,) = cluster.deploy(instance_count=1)
+    i1.sql("""create user "alice" with password 'topsecret'""")
+    i1.sql("""create user "bob" with password 'totallysecret'""")
+
+    create_table_friends_of_peppa = """
+        create table "friends_of_peppa" (
+            "name" string not null,
+            "species" string not null,
+            primary key ("name")
+        ) using memtx distributed globally
+        option (timeout = 3)
+    """
+
+    with pytest.raises(
+        ReturnError,
+        match="Create access to space 'friends_of_peppa' is denied for user 'alice'",
+    ):
+        i1.sql(create_table_friends_of_peppa, **as_alice)
+
+    # Alice can create a global table
+    i1.sudo_sql("""grant create table to "alice" """)
+    assert i1.sql(create_table_friends_of_peppa, **as_alice) == {"row_count": 1}
+
+    # Alice can write it
+    _ = cluster.cas("insert", "friends_of_peppa", ["Rebecca", "Rabbit"], **as_alice)
+    _ = cluster.cas("insert", "friends_of_peppa", ["Zoe", "Zebra"], **as_alice)
+    ret = cluster.cas("insert", "friends_of_peppa", ["Suzy", "Sheep"], **as_alice)
+    i1.raft_wait_index(ret, _3_SEC)
+
+    # Alice can read it
+    assert i1.sql("""select * from "friends_of_peppa" """, **as_alice)["rows"] == [
+        ["Rebecca", "Rabbit"],
+        ["Suzy", "Sheep"],
+        ["Zoe", "Zebra"],
+    ]
+
+    # Bob can't read it by default
+    with pytest.raises(
+        ReturnError,
+        match="Read access to space 'friends_of_peppa' is denied for user 'bob'",
+    ):
+        i1.sql("""select * from "friends_of_peppa" """, **as_bob)
+
+    # Alice can grant a read privilege to Bob
+    assert i1.sql(
+        """grant read on table "friends_of_peppa" to "bob";""", **as_alice
+    ) == {"row_count": 1}
+
+    # Now bob can read it
+    assert i1.sql(
+        """select * from "friends_of_peppa" where "name" = 'Zoe';""", **as_bob
+    )["rows"] == [["Zoe", "Zebra"]]
+
+    # But Bob still can't write it
+    with pytest.raises(
+        ReturnError,
+        match="Write access to space 'friends_of_peppa' is denied for user 'bob'",
+    ):
+        cluster.cas("delete", "friends_of_peppa", key=["Rebecca"], **as_bob)
+
+
+def test_access_sharded_table(cluster: Cluster):
+    (i1,) = cluster.deploy(instance_count=1)
+    i1.sql("""create user "alice" with password 'topsecret'""")
+    i1.sql("""create user "bob" with password 'totallysecret'""")
+
+    create_table_wonderland = """
+        create table "wonderland" (
+            "creature" text not null,
+            "count" integer,
+            primary key ("creature")
+        ) using memtx distributed by ("creature")
+        option (timeout = 3.0)
+    """
+
+    with pytest.raises(
+        ReturnError,
+        match="Create access to space 'wonderland' is denied for user 'alice'",
+    ):
+        i1.sql(create_table_wonderland, **as_alice)
+
+    # Alice can create a global table
+    assert i1.sudo_sql("""grant create table to "alice";""") == {"row_count": 1}
+    assert i1.sql(create_table_wonderland, **as_alice) == {"row_count": 1}
+
+    # Alice can write it
+    i1.sql("""insert into "wonderland" values ('dragon', 13)""", **as_alice)
+    i1.sql("""insert into "wonderland" values ('unicorn', 4)""", **as_alice)
+    i1.sql("""insert into "wonderland" values ('goblin', null)""", **as_alice)
+
+    # Alice can read it
+    assert i1.sql("""select * from "wonderland";""", **as_alice)["rows"] == [
+        ["dragon", 13],
+        ["goblin", None],
+        ["unicorn", 4],
+    ]
+
+    # Bob can't read it by default
+    with pytest.raises(
+        ReturnError,
+        match="Read access to space 'wonderland' is denied for user 'bob'",
+    ):
+        i1.sql("""select * from "wonderland" """, **as_bob)
+
+    # Alice can grant a read privilege to Bob
+    assert i1.sql("""grant read on table "wonderland" to "bob";""", **as_alice) == {
+        "row_count": 1
+    }
+
+    # Now bob can read it
+    assert i1.sql(
+        """select * from "wonderland" where "creature" = 'unicorn';""", **as_bob
+    )["rows"] == [["unicorn", 4]]
+
+    # But Bob still can't write it
+    with pytest.raises(
+        ReturnError,
+        match="Write access to space 'wonderland' is denied for user 'bob'",
+    ):
+        i1.sql("""insert into "wonderland" values ('snail', 1)""", **as_bob)