diff --git a/search_api_db.test b/search_api_db.test
index 7c65a99..5cb9db2 100644
--- a/search_api_db.test
+++ b/search_api_db.test
@@ -46,6 +46,8 @@ class SearchApiDbTest extends DrupalWebTestCase {
     $this->indexItems();
     $this->searchSuccess1();
     $this->regressionTests();
+    $this->editServerPartial();
+    $this->searchSuccessPartial();
     $this->editServer();
     $this->searchSuccess2();
     $this->clearIndex();
@@ -59,14 +61,14 @@ class SearchApiDbTest extends DrupalWebTestCase {
     $count = db_query('SELECT COUNT(*) FROM {search_api_test}')->fetchField();
     $this->insertItem(array(
       'id' => 1,
-      'title' => 'foo bar baz',
+      'title' => 'foo bar baz foobaz',
       'body' => 'test test',
       'type' => 'item',
       'keywords' => 'orange',
     ));
     $this->insertItem(array(
       'id' => 2,
-      'title' => 'foo test',
+      'title' => 'foo test foobuz',
       'body' => 'bar test',
       'type' => 'item',
       'keywords' => 'orange,apple,grape',
@@ -119,6 +121,7 @@ class SearchApiDbTest extends DrupalWebTestCase {
       'options' => array(
         'min_chars' => 3,
         'database' => $database,
+        'partial_string_search' => FALSE,
       ),
     );
     $success = (bool) entity_create('search_api_server', $values)->save();
@@ -241,6 +244,7 @@ class SearchApiDbTest extends DrupalWebTestCase {
   protected function editServer() {
     $server = search_api_server_load($this->server_id, TRUE);
     $server->options['min_chars'] = 4;
+    $server->options['partial_string_search'] = FALSE;
     $success = (bool) $server->save();
     $this->assertTrue($success, 'The server was successfully edited.');
 
@@ -341,6 +345,39 @@ class SearchApiDbTest extends DrupalWebTestCase {
     $this->assertEqual($results['warnings'], array(), 'No warnings were displayed.');
   }
 
+  protected function editServerPartial() {
+    $server = search_api_server_load($this->server_id, TRUE);
+    $server->options['partial_string_search'] = TRUE;
+    $success = (bool) $server->save();
+    $this->assertTrue($success, 'The server was successfully edited.');
+
+    $this->clearIndex();
+    $this->indexItems();
+
+    // Reset the internal cache so the new values will be available.
+    search_api_index_load($this->index_id, TRUE);
+  }
+
+  protected function searchSuccessPartial() {
+    $results = $this->buildSearch('foobaz')->range(0, 1)->execute();
+    $this->assertEqual($results['result count'], 1, 'Partial search for »foobaz« returned correct number of results.');
+    $this->assertEqual(array_keys($results['results']), array(1), 'Partial search for »foobaz« returned correct result.');
+    $this->assertEqual($results['ignored'], array(), 'No keys were ignored.');
+    $this->assertEqual($results['warnings'], array(), 'No warnings were displayed.');
+
+    $results = $this->buildSearch('foo')->execute();
+    $this->assertEqual($results['result count'], 5, 'Partial search for »foo« returned correct number of results.');
+    $this->assertEqual(array_keys($results['results']), array(1, 2, 4, 3, 5), 'Partial search for »foo« returned correct result.');
+    $this->assertEqual($results['ignored'], array(), 'No keys were ignored.');
+    $this->assertEqual($results['warnings'], array(), 'No warnings were displayed.');
+
+    $results = $this->buildSearch('foo', array('type,item'))->sort('id', 'DESC')->execute();
+    $this->assertEqual($results['result count'], 2, 'Partial search for »foo« of type »item« returned correct number of results.');
+    $this->assertEqual(array_keys($results['results']), array(2, 1), 'Partial search for »foo« of type »item« returned correct result.');
+    $this->assertEqual($results['ignored'], array(), 'No keys were ignored.');
+    $this->assertEqual($results['warnings'], array(), 'No warnings were displayed.');
+  }
+
   /**
    * Executes regression tests for issues that were already fixed.
    */
diff --git a/service.inc b/service.inc
index b70db27..9b484f8 100644
--- a/service.inc
+++ b/service.inc
@@ -92,6 +92,7 @@ class SearchApiDbService extends SearchApiAbstractService {
     $options = $this->options + array(
       'min_chars' => 1,
       'autocomplete' => array(),
+      'partial_string_search' => FALSE,
     );
     $options['autocomplete'] += array(
       'suggest_suffix' => TRUE,
@@ -106,6 +107,13 @@ class SearchApiDbService extends SearchApiAbstractService {
       '#default_value' => $options['min_chars'],
     );
 
+    $form['partial_string_search'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Search on parts of a word'),
+      '#description' => t('Search on a part of the word (e.g. `base` in the word `database`).'),
+      '#default_value' => $options['partial_string_search'],
+    );
+
     if (module_exists('search_api_autocomplete')) {
       $form['autocomplete'] = array(
         '#type' => 'fieldset',
@@ -1340,6 +1348,7 @@ class SearchApiDbService extends SearchApiAbstractService {
     $db_query = NULL;
     $mul_words = FALSE;
     $neg_nested = $neg && $conj == 'AND';
+    $partial = $this->options['partial_string_search'];
 
     foreach ($keys as $i => $key) {
       if (!element_child($i)) {
@@ -1380,7 +1389,26 @@ class SearchApiDbService extends SearchApiAbstractService {
       else {
         $db_query->fields('t', array('item_id', 'word', 'score'));
       }
-      $db_query->condition('word', $words, 'IN');
+
+      if (!$partial) {
+        $db_query->condition('word', $words, 'IN');
+      }
+      else {
+        $db_or = db_or();
+        foreach ($words as $i => $word) {
+          $alias = 'w' . $i;
+          $db_or->condition('t.word', '%' . db_like($word) . '%', 'LIKE');
+
+
+          // Add an expression for each word that we are searching on and group
+          // by it such that we won't get duplicate entries if the partial
+          // string occurs multiple times.
+          $db_query->addExpression("t.word LIKE '%" . db_like($word) . "%'", $alias);
+          $db_query->groupBy('t.item_id');
+          $db_query->groupBy($alias);
+        }
+        $db_query->condition($db_or);
+      }
       $db_query->condition('field_name', array_map(array(__CLASS__, 'getTextFieldName'), array_keys($fields)), 'IN');
     }
 
@@ -1664,6 +1692,10 @@ class SearchApiDbService extends SearchApiAbstractService {
     }
     $expressions = &$db_query->getExpressions();
     $expressions = array();
+
+    $group_by = &$db_query->getGroupBy();
+    $group_by = array();
+
     $db_query->distinct();
     if (!$db_query->preExecute()) {
       return FALSE;
