diff --git a/docs/api/database.rst b/docs/api/database.rst
index 2477bcebe22cfc9499c29feec880a915cf33bf4a..2733b4ab985434d2b1df46c55a10a4922e218631 100644
--- a/docs/api/database.rst
+++ b/docs/api/database.rst
@@ -238,7 +238,7 @@ Database object
         ``largest_seqno``
             largest seqno in file
 
-    .. py:method:: compact_range(begin=None, end=None, reduce_level=False, target_level=-1)
+    .. py:method:: compact_range(begin=None, end=None, ** options)
 
         Compact the underlying storage for the key range [begin,end].
         The actual compaction interval might be superset of [begin, end].
@@ -256,7 +256,7 @@ Database object
         Note that after the entire database is compacted, all data are pushed
         down to the last level containing any data. If the total data size
         after compaction is reduced, that level might not be appropriate for
-        hosting all the files. In this case, client could set reduce_level
+        hosting all the files. In this case, client could set change_level
         to ``True``, to move the files back to the minimum level capable of holding
         the data set or a given level (specified by non-negative target_level).
 
@@ -264,11 +264,29 @@ Database object
                             If ``None`` start at the beginning of the database.
         :param bytes end: Key where to end compaction.
                           If ``None`` end at the last key of the database.
-        :param bool reduce_level:  If ``True`` allow rocksdb to move the data to
-                                   another level, if the current is not big enouth.
+        :param bool change_level:  If ``True``, compacted files will be moved to
+                                   the minimum level capable of holding the data
+                                   or given level (specified by non-negative target_level).
                                    If ``False`` you may end with a bigger level
-                                   than configured.
-        :param int target_level: Level where to push the the range to compact.
+                                   than configured. Default is ``False``.
+        :param int target_level: If change_level is true and target_level have non-negative
+                                 value, compacted files will be moved to target_level.
+                                 Default is ``-1``.
+        :param string bottommost_level_compaction:
+            For level based compaction, we can configure if we want to
+            skip/force bottommost level compaction. By default level based
+            compaction will only compact the bottommost level if there is a
+            compaction filter. It can be set to the following values.
+
+            ``skip``
+                Skip bottommost level compaction
+
+            ``if_compaction_filter``
+                Only compact bottommost level if there is a compaction filter.
+                This is the default.
+
+            ``force``
+                Always compact bottommost level
         
     .. py:attribute:: options
 
diff --git a/docs/changelog.rst b/docs/changelog.rst
index 654ad9d69d695076935875766c48665cd6fb647e..44f847976dabc46c246e484a2b09e5a1a5e9a023 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -4,7 +4,16 @@ Changelog
 Version 0.4
 -----------
 
-*  Added :py:func:`repair_db`
+* Added :py:func:`repair_db`.
+
+Backward Incompatible Changes:
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* Changed API of :py:meth:`rocksdb.DB.compact_range`.
+
+    * Only allow keyword arguments.
+    * Changed ``reduce_level`` to ``change_level``.
+    * Add new argument called ``bottommost_level_compaction``.
 
 
 Version 0.3
diff --git a/rocksdb/_rocksdb.pyx b/rocksdb/_rocksdb.pyx
index 99e841aae317c68f9c1dd80902dbfd9b15d039e6..2cb8b3abc254d69afdc226ccb1e0e767b3a828b6 100644
--- a/rocksdb/_rocksdb.pyx
+++ b/rocksdb/_rocksdb.pyx
@@ -1557,7 +1557,21 @@ cdef class DB(object):
 
         return ret
 
-    def compact_range(self, begin=None, end=None, reduce_level=False, target_level=-1):
+    def compact_range(self, begin=None, end=None, **py_options):
+        cdef options.CompactRangeOptions c_options
+
+        c_options.change_level = py_options.get('change_level', False)
+        c_options.target_level = py_options.get('target_level', -1)
+
+        blc = py_options.get('bottommost_level_compaction', 'if_compaction_filter')
+        if blc == 'skip':
+            c_options.bottommost_level_compaction = options.blc_skip
+        elif blc == 'if_compaction_filter':
+            c_options.bottommost_level_compaction = options.blc_is_filter
+        elif blc == 'force':
+            c_options.bottommost_level_compaction = options.blc_force
+        else:
+            raise ValueError("bottommost_level_compaction is not valid")
 
         cdef Status st
         cdef Slice begin_val
@@ -1577,12 +1591,7 @@ cdef class DB(object):
             end_val = bytes_to_slice(end)
             end_ptr = cython.address(end_val)
 
-
-        st = self.db.CompactRange(
-            begin_ptr,
-            end_ptr,
-            reduce_level,
-            target_level)
+        st = self.db.CompactRange(c_options, begin_ptr, end_ptr)
         check_status(st)
 
     @staticmethod
diff --git a/rocksdb/db.pxd b/rocksdb/db.pxd
index afd444f879546fb45375ae76d10af5501c1d75d0..a83786ba66de46cf4562c436884c74820c8e9430 100644
--- a/rocksdb/db.pxd
+++ b/rocksdb/db.pxd
@@ -106,10 +106,9 @@ cdef extern from "rocksdb/db.h" namespace "rocksdb":
             uint64_t*) nogil except+
 
         Status CompactRange(
+            const options.CompactRangeOptions&,
             const Slice*,
-            const Slice*,
-            cpp_bool,
-            int) nogil except+
+            const Slice*) nogil except+
 
         int NumberLevels() nogil except+
         int MaxMemCompactionLevel() nogil except+
diff --git a/rocksdb/options.pxd b/rocksdb/options.pxd
index de8db40bca2e34faecb4e024062af1783e29b982..ea1daafa848fff944e4a6df04a78b50353de4af3 100644
--- a/rocksdb/options.pxd
+++ b/rocksdb/options.pxd
@@ -2,6 +2,7 @@ from libcpp cimport bool as cpp_bool
 from libcpp.string cimport string
 from libcpp.vector cimport vector
 from libc.stdint cimport uint64_t
+from libc.stdint cimport uint32_t
 from std_memory cimport shared_ptr
 from comparator cimport Comparator
 from merge_operator cimport MergeOperator
@@ -117,3 +118,14 @@ cdef extern from "rocksdb/options.h" namespace "rocksdb":
 
     cdef cppclass FlushOptions:
         cpp_bool wait
+
+    ctypedef enum BottommostLevelCompaction:
+        blc_skip "rocksdb::BottommostLevelCompaction::kSkip"
+        blc_is_filter "rocksdb::BottommostLevelCompaction::kIfHaveCompactionFilter"
+        blc_force "rocksdb::BottommostLevelCompaction::kForce"
+
+    cdef cppclass CompactRangeOptions:
+        cpp_bool change_level
+        int target_level
+        uint32_t target_path_id
+        BottommostLevelCompaction bottommost_level_compaction