diff --git a/trac/db/sqlite_backend.py b/trac/db/sqlite_backend.py
--- a/trac/db/sqlite_backend.py
+++ b/trac/db/sqlite_backend.py
@@ -35,7 +35,11 @@
         import sqlite3 as sqlite
         have_pysqlite = 2
     except ImportError:
-        have_pysqlite = 0
+        try:
+            import sqlite
+            have_pysqlite = 1
+        except ImportError:
+            have_pysqlite = 0
 
 if have_pysqlite == 2:
     # Force values to integers because PySQLite 2.2.0 had (2, 2, '0')
@@ -102,6 +106,27 @@
             return result
 
 
+elif have_pysqlite == 1:
+    sqlite_version = sqlite._sqlite.sqlite_version_info()
+    sqlite_version_string = '%d.%d.%d' % sqlite_version
+
+    class SQLiteUnicodeCursor(sqlite.Cursor):
+        def _convert_row(self, row):
+            return tuple([(isinstance(v, str) and [v.decode('utf-8')] or [v])[0]
+                          for v in row])
+        def fetchone(self):
+            row = sqlite.Cursor.fetchone(self)
+            return row and self._convert_row(row) or None
+        def fetchmany(self, num):
+            rows = sqlite.Cursor.fetchmany(self, num)
+            return rows != None and [self._convert_row(row)
+                                     for row in rows] or []
+        def fetchall(self):
+            rows = sqlite.Cursor.fetchall(self)
+            return rows != None and [self._convert_row(row)
+                                     for row in rows] or []
+
+
 # Mapping from "abstract" SQL types to DB-specific types
 _type_map = {
     'int': 'integer',
@@ -152,14 +177,13 @@
     def get_supported_schemes(self):
         if not have_pysqlite:
             self.error = _("Cannot load Python bindings for SQLite")
-        elif sqlite_version >= (3, 3, 3):
-            if sqlite.version_info < (1, 1, 7):
-                self.error = _("Need at least PySqlite %(version)s or higher",
-                               version='1.1.7')
-            elif sqlite.version_info[0] == 2 and \
+        elif sqlite.version_info < (1, 1, 7):
+            self.error = _("Need at least PySqlite %(version)s or higher",
+                           version='1.1.7')
+        elif sqlite_version >= (3, 3, 3) and sqlite.version_info[0] == 2 and \
                     sqlite.version_info < (2, 0, 7):
-                self.error = _("Need at least PySqlite %(version)s or higher",
-                               version='2.0.7')
+            self.error = _("Need at least PySqlite %(version)s or higher",
+                           version='2.0.7')
         yield ('sqlite', self.error and -1 or 1)
 
     def get_connection(self, path, log=None, params={}):
@@ -254,15 +278,20 @@
                       'and the directory it is located in.',
                       user=getuser(), path=path))
 
-        self._active_cursors = weakref.WeakKeyDictionary()
-        timeout = int(params.get('timeout', 10.0))
-        self._eager = params.get('cursor', 'eager') == 'eager'
-        # eager is default, can be turned off by specifying ?cursor=
-        if isinstance(path, unicode): # needed with 2.4.0
-            path = path.encode('utf-8')
-        cnx = sqlite.connect(path, detect_types=sqlite.PARSE_DECLTYPES,
-                             check_same_thread=sqlite_version < (3, 3, 1),
-                             timeout=timeout)
+        if have_pysqlite == 2:
+            self._active_cursors = weakref.WeakKeyDictionary()
+            timeout = int(params.get('timeout', 10.0))
+            self._eager = params.get('cursor', 'eager') == 'eager'
+            # eager is default, can be turned off by specifying ?cursor=
+            if isinstance(path, unicode): # needed with 2.4.0
+                path = path.encode('utf-8')
+            cnx = sqlite.connect(path, detect_types=sqlite.PARSE_DECLTYPES,
+                                 check_same_thread=sqlite_version < (3, 3, 1),
+                                 timeout=timeout)
+        else:
+            timeout = int(params.get('timeout', 10000))
+            cnx = sqlite.connect(path, timeout=timeout, encoding='utf-8')
+            
         # load extensions
         extensions = params.get('extensions', [])
         if len(extensions) > 0:
@@ -273,16 +302,23 @@
        
         ConnectionWrapper.__init__(self, cnx, log)
 
-    def cursor(self):
-        cursor = self.cnx.cursor((PyFormatCursor, EagerCursor)[self._eager])
-        self._active_cursors[cursor] = True
-        cursor.cnx = self
-        return IterableCursor(cursor, self.log)
+    if have_pysqlite == 2:
+        def cursor(self):
+            cursor = self.cnx.cursor((PyFormatCursor, EagerCursor)[self._eager])
+            self._active_cursors[cursor] = True
+            cursor.cnx = self
+            return IterableCursor(cursor, self.log)
 
-    def rollback(self):
-        for cursor in self._active_cursors.keys():
-            cursor.close()
-        self.cnx.rollback()
+        def rollback(self):
+            for cursor in self._active_cursors.keys():
+                cursor.close()
+            self.cnx.rollback()
+
+    else:
+        def cursor(self):
+            self.cnx._checkNotClosed("cursor")
+            cursor = SQLiteUnicodeCursor(self.cnx, self.cnx.rowclass)
+            return IterableCursor(cursor, self.log)
 
     def cast(self, column, type):
         if sqlite_version >= (3, 2, 3):
@@ -313,5 +349,9 @@
         """Return the quoted identifier."""
         return "`%s`" % identifier
 
-    def get_last_id(self, cursor, table, column='id'):
-        return cursor.lastrowid
+    if have_pysqlite == 2:
+        def get_last_id(self, cursor, table, column='id'):
+            return cursor.lastrowid
+    else:
+        def get_last_id(self, cursor, table, column='id'):
+            return self.cnx.db.sqlite_last_insert_rowid()

