diff --git a/changelogs/unreleased/add-granularity-option.md b/changelogs/unreleased/add-granularity-option.md
new file mode 100644
index 0000000000000000000000000000000000000000..bf6ba8a6d16c8b6b7d4d98950dfe71c585aefa27
--- /dev/null
+++ b/changelogs/unreleased/add-granularity-option.md
@@ -0,0 +1,5 @@
+## feature/core
+
+* Added granularity option to box.cfg{}. Granularity is an option
+  that allows user to set multiplicity of memory allocation in small
+  allocator. Granulatiry must be exponent of two and >= 4 (gh-5518).
diff --git a/src/box/box.cc b/src/box/box.cc
index 26cbe8aab92be92bcc3383df6921c3ec0d132a24..b4a1a5e07c0c3b820c15b811e993c33c2dac5557 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -849,6 +849,30 @@ box_check_sql_cache_size(int size)
 	return 0;
 }
 
+static void
+box_check_small_alloc_options(void)
+{
+	/*
+	 * If we use the int type, we may get an incorrect
+	 * result if the user enters a large value.
+	 */
+	int64_t granularity = cfg_geti64("granularity");
+	/*
+	 * Granularity must be exponent of two and >= 4.
+	 * We can use granularity value == 4 only because we used small
+	 * memory allocator only for struct tuple, which doesn't require
+	 * aligment. Also added an upper bound for granularity, since if
+	 * the user enters too large value, he will get incomprehensible
+	 * errors later.
+	 */
+	if (granularity < 4 || granularity > 1024 * 16 ||
+	    ! is_exp_of_two(granularity))
+		tnt_raise(ClientError, ER_CFG, "granularity",
+			  "must be greater than or equal to 4,"
+			  " less than or equal"
+			  " to 1024 * 16 and exponent of two");
+}
+
 void
 box_check_config(void)
 {
@@ -878,6 +902,7 @@ box_check_config(void)
 	if (box_check_memory_quota("memtx_memory") < 0)
 		diag_raise();
 	box_check_memtx_min_tuple_size(cfg_geti64("memtx_min_tuple_size"));
+	box_check_small_alloc_options();
 	box_check_vinyl_options();
 	if (box_check_sql_cache_size(cfg_geti("sql_cache_size")) != 0)
 		diag_raise();
@@ -2541,6 +2566,7 @@ engine_init()
 				    cfg_getd("memtx_memory"),
 				    cfg_geti("memtx_min_tuple_size"),
 				    cfg_geti("strip_core"),
+				    cfg_geti("granularity"),
 				    cfg_getd("slab_alloc_factor"));
 	engine_register((struct engine *)memtx);
 	box_set_memtx_max_tuple_size();
diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua
index 574c8bef4a850278da3428c77e1264e59a7985d5..aac216932844c6b745916666b27eaa64857cf830 100644
--- a/src/box/lua/load_cfg.lua
+++ b/src/box/lua/load_cfg.lua
@@ -42,6 +42,7 @@ local default_cfg = {
     strip_core          = true,
     memtx_min_tuple_size = 16,
     memtx_max_tuple_size = 1024 * 1024,
+    granularity         = 8,
     slab_alloc_factor   = 1.05,
     work_dir            = nil,
     memtx_dir           = ".",
@@ -123,6 +124,7 @@ local template_cfg = {
     strip_core          = 'boolean',
     memtx_min_tuple_size  = 'number',
     memtx_max_tuple_size  = 'number',
+    granularity         = 'number',
     slab_alloc_factor   = 'number',
     work_dir            = 'string',
     memtx_dir            = 'string',
diff --git a/src/box/memtx_engine.c b/src/box/memtx_engine.c
index a4cd671f59798219c31dc5110bb630d885f3ad50..7d4c3789c5908a14092e7028dd68cd9817a282ce 100644
--- a/src/box/memtx_engine.c
+++ b/src/box/memtx_engine.c
@@ -1064,7 +1064,7 @@ memtx_engine_gc_f(va_list va)
 struct memtx_engine *
 memtx_engine_new(const char *snap_dirname, bool force_recovery,
 		 uint64_t tuple_arena_max_size, uint32_t objsize_min,
-		 bool dontdump, float alloc_factor)
+		 bool dontdump, unsigned granularity, float alloc_factor)
 {
 	struct memtx_engine *memtx = calloc(1, sizeof(*memtx));
 	if (memtx == NULL) {
@@ -1133,7 +1133,8 @@ memtx_engine_new(const char *snap_dirname, bool force_recovery,
 	slab_cache_create(&memtx->slab_cache, &memtx->arena);
 	float actual_alloc_factor;
 	small_alloc_create(&memtx->alloc, &memtx->slab_cache,
-			   objsize_min, alloc_factor, &actual_alloc_factor);
+			   objsize_min, granularity, alloc_factor,
+			   &actual_alloc_factor);
 	say_info("Actual slab_alloc_factor calculated on the basis of desired "
 		 "slab_alloc_factor = %f", actual_alloc_factor);
 
diff --git a/src/box/memtx_engine.h b/src/box/memtx_engine.h
index 8b380bf3ccc5f7335d7d94e74403899ac005e8cf..8bf35b5a4b668d17f32cde2cf4231970d102e7e1 100644
--- a/src/box/memtx_engine.h
+++ b/src/box/memtx_engine.h
@@ -213,7 +213,7 @@ struct memtx_engine *
 memtx_engine_new(const char *snap_dirname, bool force_recovery,
 		 uint64_t tuple_arena_max_size,
 		 uint32_t objsize_min, bool dontdump,
-		 float alloc_factor);
+		 unsigned granularity, float alloc_factor);
 
 int
 memtx_engine_recover_snapshot(struct memtx_engine *memtx,
@@ -299,13 +299,13 @@ static inline struct memtx_engine *
 memtx_engine_new_xc(const char *snap_dirname, bool force_recovery,
 		    uint64_t tuple_arena_max_size,
 		    uint32_t objsize_min, bool dontdump,
-		    float alloc_factor)
+		    unsigned granularity, float alloc_factor)
 {
 	struct memtx_engine *memtx;
 	memtx = memtx_engine_new(snap_dirname, force_recovery,
 				 tuple_arena_max_size,
 				 objsize_min, dontdump,
-				 alloc_factor);
+				 granularity, alloc_factor);
 	if (memtx == NULL)
 		diag_raise();
 	return memtx;
diff --git a/src/box/tuple.c b/src/box/tuple.c
index c2023e4e8f41ca386d26001150f7fef0584649d5..47330481440039c8f6fe0afb0efc11794ade6a2a 100644
--- a/src/box/tuple.c
+++ b/src/box/tuple.c
@@ -315,7 +315,8 @@ tuple_init(field_name_hash_f hash)
 
 	float actual_alloc_factor;
 	small_alloc_create(&runtime_alloc, &cord()->slabc, OBJSIZE_MIN,
-			   ALLOC_FACTOR, &actual_alloc_factor);
+			   sizeof(intptr_t), ALLOC_FACTOR,
+			   &actual_alloc_factor);
 
 	mempool_create(&tuple_iterator_pool, &cord()->slabc,
 		       sizeof(struct tuple_iterator));
diff --git a/src/lib/small b/src/lib/small
index 3ae6cbb4b51bb327aea30acaa83098bb25b03156..8ef2ec4b383e3b518fbfc462eee8d9c9786c3a64 160000
--- a/src/lib/small
+++ b/src/lib/small
@@ -1 +1 @@
-Subproject commit 3ae6cbb4b51bb327aea30acaa83098bb25b03156
+Subproject commit 8ef2ec4b383e3b518fbfc462eee8d9c9786c3a64
diff --git a/src/trivia/util.h b/src/trivia/util.h
index 15f9881db873c32e094c9c740537c9fd8a999cc1..899e1eb7dbe1ce9ecbbdf9b6da4be9c188d4ecc9 100644
--- a/src/trivia/util.h
+++ b/src/trivia/util.h
@@ -39,6 +39,7 @@
 #include <unistd.h>
 #include <inttypes.h>
 #include <assert.h>
+#include <stdbool.h>
 
 #if defined(__cplusplus)
 extern "C" {
@@ -563,6 +564,12 @@ cmp_i64(const void *_a, const void *_b)
 	return COMPARE_RESULT(*a, *b);
 }
 
+static inline bool
+is_exp_of_two(unsigned n)
+{
+	return (n & (n - 1)) == 0;
+}
+
 /**
  * Put the current thread in sleep for the given number of
  * seconds.
diff --git a/test/app-tap/init_script.result b/test/app-tap/init_script.result
index 16c5b01d240ad98c01b7da077171ac6115abb73f..76fe2ea272cf3a9aca7a7f645a7be0183cde9146 100644
--- a/test/app-tap/init_script.result
+++ b/test/app-tap/init_script.result
@@ -15,6 +15,7 @@ feedback_enabled:true
 feedback_host:https://feedback.tarantool.io
 feedback_interval:3600
 force_recovery:false
+granularity:8
 hot_standby:false
 listen:port
 log:tarantool.log
diff --git a/test/box/admin.result b/test/box/admin.result
index 05debe67317f65854ddf0670ccadbeedb0c98f8a..c9a6ff9e48616df56bff9af6af21c931da3b4f49 100644
--- a/test/box/admin.result
+++ b/test/box/admin.result
@@ -51,6 +51,8 @@ cfg_filter(box.cfg)
     - 3600
   - - force_recovery
     - false
+  - - granularity
+    - 8
   - - hot_standby
     - false
   - - listen
diff --git a/test/box/cfg.result b/test/box/cfg.result
index 22a720c2cdd36c4f2237cce6194c135747d7ffc1..ae37b28f07c08b2df0fd1a8fc3a9809ada0e8a08 100644
--- a/test/box/cfg.result
+++ b/test/box/cfg.result
@@ -39,6 +39,8 @@ cfg_filter(box.cfg)
  |     - 3600
  |   - - force_recovery
  |     - false
+ |   - - granularity
+ |     - 8
  |   - - hot_standby
  |     - false
  |   - - listen
@@ -154,6 +156,8 @@ cfg_filter(box.cfg)
  |     - 3600
  |   - - force_recovery
  |     - false
+ |   - - granularity
+ |     - 8
  |   - - hot_standby
  |     - false
  |   - - listen
diff --git a/test/box/gh-5518-add-granularity-option.lua b/test/box/gh-5518-add-granularity-option.lua
new file mode 100644
index 0000000000000000000000000000000000000000..d040b677bd9132a4896bcb31fde221ea0c3a8069
--- /dev/null
+++ b/test/box/gh-5518-add-granularity-option.lua
@@ -0,0 +1,20 @@
+#!/usr/bin/env tarantool
+
+local granularity = 8
+if arg[1] then
+    granularity = tonumber(arg[1])
+end
+
+require('console').listen(os.getenv('ADMIN'))
+
+box.cfg({
+    listen = os.getenv("LISTEN"),
+    granularity = granularity,
+})
+
+if box.space.test ~= nil then
+    box.space.test:drop()
+end
+local s = box.schema.space.create('test')
+local _ = s:create_index('test')
+for i = 1, 1000 do s:insert{i, i + 1} end
diff --git a/test/box/gh-5518-add-granularity-option.result b/test/box/gh-5518-add-granularity-option.result
new file mode 100644
index 0000000000000000000000000000000000000000..eeb2fad5da065818daf2660e8e5132c721c28d2b
--- /dev/null
+++ b/test/box/gh-5518-add-granularity-option.result
@@ -0,0 +1,144 @@
+-- test-run result file version 2
+env = require('test_run')
+ | ---
+ | ...
+test_run = env.new()
+ | ---
+ | ...
+
+test_run:cmd("setopt delimiter ';'")
+ | ---
+ | - true
+ | ...
+function check_slab_stats(slab_stats, granularity)
+    for _, stats in pairs(slab_stats) do
+        assert(type(stats) == "table")
+        for key, value in pairs(stats) do
+            if key == "item_size" then
+                assert((value % granularity) == 0)
+            end
+        end
+    end
+end;
+ | ---
+ | ...
+function get_slab_info_and_check_stats(granularity)
+    local slab_stats = test_run:eval('test', "box.slab.stats()")
+    local slab_info = test_run:eval('test', "box.slab.info()")
+    check_slab_stats(slab_stats[1], granularity)
+    return slab_info[1]
+end;
+ | ---
+ | ...
+test_run:cmd('create server test with script=\z
+             "box/gh-5518-add-granularity-option.lua"');
+ | ---
+ | - true
+ | ...
+test_run:cmd("setopt delimiter ''");
+ | ---
+ | - true
+ | ...
+-- Start server test with granularity == 2 failed
+-- (must be greater than or equal to 4)
+test_run:cmd('start server test with args="2" with crash_expected=True')
+ | ---
+ | - false
+ | ...
+-- Start server test with granularity == 7 failed
+-- (must be exponent of 2)
+test_run:cmd('start server test with args="7" with crash_expected=True')
+ | ---
+ | - false
+ | ...
+
+test_run:cmd('start server test with args="4"')
+ | ---
+ | - true
+ | ...
+-- Granularity determines not only alignment of objects,
+-- but also size of the objects in the pool. Thus, the greater
+-- the granularity, the greater the memory loss per one memory allocation,
+-- but tuples with different sizes are allocated from the same mempool,
+-- and we do not lose memory on the slabs, when we have highly
+-- distributed tuple sizes. This is somewhat similar to a large alloc factor
+
+-- Try to insert/delete to space, in case when UB sanitizer on,
+-- we check correct memory aligment
+slab_info_4 = get_slab_info_and_check_stats(4)
+ | ---
+ | ...
+test_run:cmd('stop server test')
+ | ---
+ | - true
+ | ...
+
+test_run:cmd('start server test with args="64"')
+ | ---
+ | - true
+ | ...
+slab_info_64 = get_slab_info_and_check_stats(64)
+ | ---
+ | ...
+test_run:cmd('stop server test')
+ | ---
+ | - true
+ | ...
+
+-- Start server test with granularity = 8192
+-- This is not a user case (such big granularity leads
+-- to an unacceptably large memory consumption).
+-- For test purposes only.
+test_run:cmd('start server test with args="8192"')
+ | ---
+ | - true
+ | ...
+slab_info_8192 = get_slab_info_and_check_stats(8192)
+ | ---
+ | ...
+test_run:cmd('stop server test')
+ | ---
+ | - true
+ | ...
+
+-- Check that the larger the granularity,
+-- the larger memory usage.
+test_run:cmd("setopt delimiter ';'")
+ | ---
+ | - true
+ | ...
+function percent_string_to_number(str)
+    local p = string.find(str, "%%")
+    return string.sub(str, 0, p - 1)
+end;
+ | ---
+ | ...
+for key, value_4 in pairs(slab_info_4) do
+    local value_64 = slab_info_64[key]
+    local value_8192 = slab_info_8192[key]
+    if (key == "items_used_ratio" or key == "arena_used_ratio") then
+        value_4 = percent_string_to_number(value_4)
+        value_64 = percent_string_to_number(value_64)
+        value_8192 = percent_string_to_number(value_8192)
+    end
+    if (key == "items_used" or key == "arena_used" or
+        key == "items_used_ratio" or key == "arena_used_ratio") then
+        assert(tonumber(value_4) < tonumber(value_64) and
+               tonumber(value_64) < tonumber(value_8192))
+    end
+end;
+ | ---
+ | ...
+test_run:cmd("setopt delimiter ''");
+ | ---
+ | - true
+ | ...
+
+test_run:cmd('cleanup server test')
+ | ---
+ | - true
+ | ...
+test_run:cmd('delete server test')
+ | ---
+ | - true
+ | ...
diff --git a/test/box/gh-5518-add-granularity-option.test.lua b/test/box/gh-5518-add-granularity-option.test.lua
new file mode 100644
index 0000000000000000000000000000000000000000..2943d50e4aad2433ef200c42b14f68c7071a47fa
--- /dev/null
+++ b/test/box/gh-5518-add-granularity-option.test.lua
@@ -0,0 +1,80 @@
+env = require('test_run')
+test_run = env.new()
+
+test_run:cmd("setopt delimiter ';'")
+function check_slab_stats(slab_stats, granularity)
+    for _, stats in pairs(slab_stats) do
+        assert(type(stats) == "table")
+        for key, value in pairs(stats) do
+            if key == "item_size" then
+                assert((value % granularity) == 0)
+            end
+        end
+    end
+end;
+function get_slab_info_and_check_stats(granularity)
+    local slab_stats = test_run:eval('test', "box.slab.stats()")
+    local slab_info = test_run:eval('test', "box.slab.info()")
+    check_slab_stats(slab_stats[1], granularity)
+    return slab_info[1]
+end;
+test_run:cmd('create server test with script=\z
+             "box/gh-5518-add-granularity-option.lua"');
+test_run:cmd("setopt delimiter ''");
+-- Start server test with granularity == 2 failed
+-- (must be greater than or equal to 4)
+test_run:cmd('start server test with args="2" with crash_expected=True')
+-- Start server test with granularity == 7 failed
+-- (must be exponent of 2)
+test_run:cmd('start server test with args="7" with crash_expected=True')
+
+test_run:cmd('start server test with args="4"')
+-- Granularity determines not only alignment of objects,
+-- but also size of the objects in the pool. Thus, the greater
+-- the granularity, the greater the memory loss per one memory allocation,
+-- but tuples with different sizes are allocated from the same mempool,
+-- and we do not lose memory on the slabs, when we have highly
+-- distributed tuple sizes. This is somewhat similar to a large alloc factor
+
+-- Try to insert/delete to space, in case when UB sanitizer on,
+-- we check correct memory aligment
+slab_info_4 = get_slab_info_and_check_stats(4)
+test_run:cmd('stop server test')
+
+test_run:cmd('start server test with args="64"')
+slab_info_64 = get_slab_info_and_check_stats(64)
+test_run:cmd('stop server test')
+
+-- Start server test with granularity = 8192
+-- This is not a user case (such big granularity leads
+-- to an unacceptably large memory consumption).
+-- For test purposes only.
+test_run:cmd('start server test with args="8192"')
+slab_info_8192 = get_slab_info_and_check_stats(8192)
+test_run:cmd('stop server test')
+
+-- Check that the larger the granularity,
+-- the larger memory usage.
+test_run:cmd("setopt delimiter ';'")
+function percent_string_to_number(str)
+    local p = string.find(str, "%%")
+    return string.sub(str, 0, p - 1)
+end;
+for key, value_4 in pairs(slab_info_4) do
+    local value_64 = slab_info_64[key]
+    local value_8192 = slab_info_8192[key]
+    if (key == "items_used_ratio" or key == "arena_used_ratio") then
+        value_4 = percent_string_to_number(value_4)
+        value_64 = percent_string_to_number(value_64)
+        value_8192 = percent_string_to_number(value_8192)
+    end
+    if (key == "items_used" or key == "arena_used" or
+        key == "items_used_ratio" or key == "arena_used_ratio") then
+        assert(tonumber(value_4) < tonumber(value_64) and
+               tonumber(value_64) < tonumber(value_8192))
+    end
+end;
+test_run:cmd("setopt delimiter ''");
+
+test_run:cmd('cleanup server test')
+test_run:cmd('delete server test')