diff --git a/search_api_db/src/Plugin/search_api/backend/Database.php b/search_api_db/src/Plugin/search_api/backend/Database.php
index 0f8fb68..229e949 100644
--- a/search_api_db/src/Plugin/search_api/backend/Database.php
+++ b/search_api_db/src/Plugin/search_api/backend/Database.php
@@ -1176,7 +1176,7 @@ protected function indexItem(IndexInterface $index, ItemInterface $item) {
 
             // Store the first 30 characters of the string as the denormalized
             // value.
-            if (strlen($denormalized_value) < 30) {
+            if (Unicode::strlen($denormalized_value) < 30) {
               $denormalized_value .= $word . ' ';
             }
 
@@ -1208,7 +1208,7 @@ protected function indexItem(IndexInterface $index, ItemInterface $item) {
               $unique_tokens[$word_base_form]['score'] += $score;
             }
           }
-          $denormalized_values[$column] = Unicode::truncateBytes(trim($denormalized_value), 30);
+          $denormalized_values[$column] = Unicode::substr(trim($denormalized_value), 0, 30);
           if ($unique_tokens) {
             $field_name = self::getTextFieldName($field_id);
             $boost = $field_info['boost'];
@@ -1324,9 +1324,9 @@ protected function convert($value, $type, $original_type, IndexInterface $index)
         $ret = array();
         foreach (preg_split('/[^\p{L}\p{N}]+/u', $value, -1, PREG_SPLIT_NO_EMPTY) as $v) {
           if ($v) {
-            if (strlen($v) > 50) {
+            if (Unicode::strlen($v) > 50) {
               $this->getLogger()->warning('An overlong word (more than 50 characters) was encountered while indexing: %word.<br />Database search servers currently cannot index such words correctly – the word was therefore trimmed to the allowed length. Ensure you are using a tokenizer preprocessor.', array('%word' => $v));
-              $v = Unicode::truncateBytes($v, 50);
+              $v = Unicode::substr($v, 0, 50);
             }
             $ret[] = array(
               'value' => $v,
@@ -1343,9 +1343,9 @@ protected function convert($value, $type, $original_type, IndexInterface $index)
             // Check for over-long tokens.
             $score = $v['score'];
             $v = $v['value'];
-            if (strlen($v) > 50) {
+            if (Unicode::strlen($v) > 50) {
               $words = preg_split('/[^\p{L}\p{N}]+/u', $v, -1, PREG_SPLIT_NO_EMPTY);
-              if (count($words) > 1 && max(array_map('strlen', $words)) <= 50) {
+              if (count($words) > 1 && max(array_map('Drupal\Component\Utility\Unicode::strlen', $words)) <= 50) {
                 // Overlong token is due to bad tokenizing.
                 // Check for "Tokenizer" preprocessor on index.
                 if (empty($index->getProcessors()['tokenizer'])) {
@@ -1358,9 +1358,9 @@ protected function convert($value, $type, $original_type, IndexInterface $index)
 
               $tokens = array();
               foreach ($words as $word) {
-                if (strlen($word) > 50) {
+                if (Unicode::strlen($word) > 50) {
                   $this->getLogger()->warning('An overlong word (more than 50 characters) was encountered while indexing: %word.<br />Database search servers currently cannot index such words correctly – the word was therefore trimmed to the allowed length.', array('%word' => $word));
-                  $word = Unicode::truncateBytes($word, 50);
+                  $word = Unicode::substr($word, 0, 50);
                 }
                 $tokens[] = array(
                   'value' => $word,
@@ -1382,8 +1382,8 @@ protected function convert($value, $type, $original_type, IndexInterface $index)
         if ($original_type == 'date') {
           return date('c', $value);
         }
-        if (strlen($value) > 255) {
-          $value = Unicode::truncateBytes($value, 255);
+        if (Unicode::strlen($value) > 255) {
+          $value = Unicode::substr($value, 0, 255);
           $this->getLogger()->warning('An overlong value (more than 255 characters) was encountered while indexing: %value.<br />Database search servers currently cannot index such values correctly – the value was therefore trimmed to the allowed length.', array('%value' => $value));
         }
         return $value;
diff --git a/search_api_db/tests/src/Kernel/BackendTest.php b/search_api_db/tests/src/Kernel/BackendTest.php
index 2263168..774b696 100644
--- a/search_api_db/tests/src/Kernel/BackendTest.php
+++ b/search_api_db/tests/src/Kernel/BackendTest.php
@@ -1105,33 +1105,89 @@ protected function regressionTests2() {
     $index->save();
     $this->indexItems($this->indexId);
 
+    $overlong_word = 'astringlongerthanfiftycharactersthatcantbeindexedasfulltext';
     \Drupal::entityTypeManager()
       ->getStorage('entity_test')
       ->create(array(
         'id' => 8,
         'name' => 'Article with long body',
         'type' => 'article',
-        'body' => 'astringlongerthanfiftycharactersthatcantbestoredbythedbbackend',
+        'body' => $overlong_word,
       ))->save();
     $count = $this->indexItems($this->indexId);
     $this->assertEquals(1, $count, 'Indexing an item with a word longer than 50 characters worked.');
 
     // Regression test for #2616268.
     $index = $this->getIndex();
-    $field = $index->getField('body')->setType('string');
-    $index->addField($field)->save();
-    $count = $this->indexItems($this->indexId);
+    $index->getField('body')->setType('string');
+    $index->save();
+    $count = $index->indexItems();
     $this->assertEquals(8, $count, 'Switching type from text to string worked.');
 
     // For a string field, 50 characters shouldn't be a problem.
-    $query = $this->buildSearch(NULL, array('body,astringlongerthanfiftycharactersthatcantbestoredbythedbbackend'));
+    $query = $this->buildSearch(NULL, array("body,$overlong_word"));
     $results = $query->execute();
     $this->assertEquals(1, $results->getResultCount(), 'Filter on new string field returned correct number of results.');
     $this->assertEquals($this->getItemIds(array(8)), array_keys($results->getResultItems()), 'Filter on new string field returned correct result.');
     $this->assertIgnored($results);
     $this->assertWarnings($results);
 
-    $index->removeField('body');
+    $index->getField('body')->setType('text');
+    $index->save();
+
+    // Regression test for #2616804.
+    // The word has 28 Unicode characters but 56 bytes. Verify that it is still
+    // indexed correctly.
+    $mb_word = 'äöüßáŧæøðđŋħĸµäöüßáŧæøðđŋħĸµ';
+    // We put the word 8 times into the body so we can also verify that the 255
+    // character limit for strings counts characters, not bytes.
+    $mb_body = implode(' ', array_fill(0, 8, $mb_word));
+    \Drupal::entityTypeManager()
+      ->getStorage('entity_test')
+      ->create(array(
+        'id' => 9,
+        'name' => 'Test item 9',
+        'type' => 'item',
+        'body' => $mb_body,
+      ))->save();
+    $count = $this->indexItems($this->indexId);
+    $this->assertEquals(9, $count, 'Indexing an item with a word with 28 multi-byte characters worked.');
+
+    $query = $this->buildSearch($mb_word);
+    $results = $query->execute();
+    $this->assertEquals(1, $results->getResultCount(), 'Search for word with 28 multi-byte characters returned correct number of results.');
+    $this->assertEquals($this->getItemIds(array(9)), array_keys($results->getResultItems()), 'Search for word with 28 multi-byte characters returned correct result.');
+    $this->assertIgnored($results);
+    $this->assertWarnings($results);
+
+    $query = $this->buildSearch($mb_word . 'ä');
+    $results = $query->execute();
+    $this->assertEquals(0, $results->getResultCount(), 'Search for unknown word with 29 multi-byte characters returned no results.');
+    $this->assertIgnored($results);
+    $this->assertWarnings($results);
+
+    // Test the same body when indexed as a string (255 characters limit should
+    // not be reached).
+    $index = $this->getIndex();
+    $index->getField('body')->setType('string');
+    $index->save();
+    $count = $index->indexItems();
+    $this->assertEquals(9, $count, 'Switching type from text to string worked.');
+
+    $query = $this->buildSearch(NULL, array("body,$mb_body"));
+    $results = $query->execute();
+    $this->assertEquals(1, $results->getResultCount(), 'Search for body with 231 multi-byte characters returned correct number of results.');
+    $this->assertEquals($this->getItemIds(array(9)), array_keys($results->getResultItems()), 'Search for body with 231 multi-byte characters returned correct result.');
+    $this->assertIgnored($results);
+    $this->assertWarnings($results);
+
+    $query = $this->buildSearch(NULL, array("body,{$mb_body}ä"));
+    $results = $query->execute();
+    $this->assertEquals(0, $results->getResultCount(), 'Search for unknown body with 232 multi-byte characters returned no results.');
+    $this->assertIgnored($results);
+    $this->assertWarnings($results);
+
+    $index->getField('body')->setType('text');
     $index->save();
   }
 
