diff --git a/kwant/builder.py b/kwant/builder.py
index 9a0bfcffbe6a03e01af674e3f29a0173b35d89b1..31019c34533e879d383192f377e857b4e74f06d1 100644
--- a/kwant/builder.py
+++ b/kwant/builder.py
@@ -2048,6 +2048,13 @@ class _VectorizedFinalizedBuilderMixin(_FinalizedBuilderMixin):
         't' (< 0) then the associated hopping is stored in term '-t - 1'.
     """
     def hamiltonian(self, i, j, *args, params=None):
+        warnings.warn(
+            "Querying individual matrix elements with 'hamiltonian' is "
+            "deprecated, and now takes O(log N) time where N is the number "
+            "of matrix elements per hamiltonian term. Query many matrix "
+            "elements at once using 'hamiltonian_term'.",
+            KwantDeprecationWarning
+        )
         site_offsets = np.cumsum([0] + [len(s) for s in self.site_arrays])
         if i == j:
             which_term = self._onsite_term_by_site_id[i]
diff --git a/kwant/operator.pyx b/kwant/operator.pyx
index 8de1cad8aae740a77bdf36b39ee7c0175cb2f02e..2a3e71edd01d492814d97dcf702216833c96fb42 100644
--- a/kwant/operator.pyx
+++ b/kwant/operator.pyx
@@ -13,6 +13,7 @@ import cython
 from operator import itemgetter
 import functools as ft
 import collections
+import warnings
 
 import numpy as np
 import tinyarray as ta
@@ -25,7 +26,9 @@ from .graph.core import DisabledFeatureError, NodeDoesNotExistError
 from .graph.defs cimport gint
 from .graph.defs import gint_dtype
 from .system import is_infinite, Site
-from ._common import UserCodeError, get_parameters, deprecate_args
+from ._common import (
+    UserCodeError, KwantDeprecationWarning, get_parameters, deprecate_args
+)
 
 
 ################ Generic Utility functions
@@ -699,7 +702,11 @@ cdef class _LocalOperator:
             return mat
 
         offsets, norbs = _get_all_orbs(self.where, self._site_ranges)
-        return  BlockSparseMatrix(self.where, offsets, norbs, get_ham)
+        # TODO: update operators to use 'hamiltonian_term' rather than
+        #       'hamiltonian'.
+        with warnings.catch_warnings():
+            warnings.simplefilter("ignore", category=KwantDeprecationWarning)
+            return  BlockSparseMatrix(self.where, offsets, norbs, get_ham)
 
     def __getstate__(self):
         return (
diff --git a/kwant/tests/test_builder.py b/kwant/tests/test_builder.py
index 575d0caf9b9b8401f1305662210491a885adea43..253c9d7cca43251dce2c608a50150b9fb2da7f4f 100644
--- a/kwant/tests/test_builder.py
+++ b/kwant/tests/test_builder.py
@@ -20,7 +20,7 @@ from numpy.testing import assert_almost_equal
 
 import kwant
 from kwant import builder, system
-from kwant._common import ensure_rng
+from kwant._common import ensure_rng, KwantDeprecationWarning
 
 
 def test_bad_keys():
@@ -590,12 +590,16 @@ def test_hamiltonian_evaluation(vectorize):
     for i in range(len(tags)):
         site = fsyst.sites[i]
         assert site in sites
-        assert fsyst.hamiltonian(i, i) == f_onsite(site)
+        with warnings.catch_warnings():
+            warnings.filterwarnings("ignore", category=KwantDeprecationWarning)
+            assert fsyst.hamiltonian(i, i) == f_onsite(site)
 
     for t, h in fsyst.graph:
         tsite = fsyst.sites[t]
         hsite = fsyst.sites[h]
-        assert fsyst.hamiltonian(t, h) == f_hopping(tsite, hsite)
+        with warnings.catch_warnings():
+            warnings.filterwarnings("ignore", category=KwantDeprecationWarning)
+            assert fsyst.hamiltonian(t, h) == f_hopping(tsite, hsite)
 
     # test when user-function raises errors
     def onsite_raises(site):
@@ -608,13 +612,18 @@ def test_hamiltonian_evaluation(vectorize):
         a, b = hop
         # exceptions are converted to kwant.UserCodeError and we add our message
         with raises(kwant.UserCodeError) as exc_info:
-            fsyst.hamiltonian(a, a)
+            with warnings.catch_warnings():
+                warnings.filterwarnings("ignore", category=KwantDeprecationWarning)
+                fsyst.hamiltonian(a, a)
         msg = 'Error occurred in user-supplied value function "onsite_raises"'
         assert msg in str(exc_info.value)
 
         for hop in [(a, b), (b, a)]:
             with raises(kwant.UserCodeError) as exc_info:
-                fsyst.hamiltonian(*hop)
+                with warnings.catch_warnings():
+                    # Ignore deprecation warnings for 'hamiltonian'
+                    warnings.filterwarnings("ignore", category=KwantDeprecationWarning)
+                    fsyst.hamiltonian(*hop)
             msg = ('Error occurred in user-supplied '
                    'value function "hopping_raises"')
             assert msg in str(exc_info.value)
@@ -682,14 +691,18 @@ def test_vectorized_hamiltonian_evaluation():
     for i in range(len(tags)):
         site = fsyst_vectorized.sites[i]
         assert site in sites
-        assert (
-            fsyst_vectorized.hamiltonian(i, i)
-            == fsyst_simple.hamiltonian(i, i))
+        with warnings.catch_warnings():
+            warnings.filterwarnings("ignore", category=KwantDeprecationWarning)
+            assert (
+                fsyst_vectorized.hamiltonian(i, i)
+                == fsyst_simple.hamiltonian(i, i))
 
     for t, h in fsyst_vectorized.graph:
-        assert (
-            fsyst_vectorized.hamiltonian(t, h)
-            == fsyst_simple.hamiltonian(t, h))
+        with warnings.catch_warnings():
+            warnings.filterwarnings("ignore", category=KwantDeprecationWarning)
+            assert (
+                fsyst_vectorized.hamiltonian(t, h)
+                == fsyst_simple.hamiltonian(t, h))
 
     # Test infinite system, including hoppings that go both ways into
     # the next cell
@@ -1419,15 +1432,25 @@ def test_argument_passing(vectorize):
 
     # test that mixing 'args' and 'params' raises TypeError
     with raises(TypeError):
-        syst.hamiltonian(0, 0, *(2, 1), params=dict(p1=2, p2=1))
+        with warnings.catch_warnings():
+            warnings.filterwarnings("ignore", category=KwantDeprecationWarning)
+            syst.hamiltonian(0, 0, *(2, 1), params=dict(p1=2, p2=1))
+
     with raises(TypeError):
-        inf_syst.hamiltonian(0, 0, *(2, 1), params=dict(p1=2, p2=1))
+        with warnings.catch_warnings():
+            warnings.filterwarnings("ignore", category=KwantDeprecationWarning)
+            inf_syst.hamiltonian(0, 0, *(2, 1), params=dict(p1=2, p2=1))
 
     # Missing parameters raises TypeError
     with raises(TypeError):
-        syst.hamiltonian(0, 0, params=dict(p1=2))
+        with warnings.catch_warnings():
+            warnings.filterwarnings("ignore", category=KwantDeprecationWarning)
+            syst.hamiltonian(0, 0, params=dict(p1=2))
+
     with raises(TypeError):
-        syst.hamiltonian_submatrix(params=dict(p1=2))
+        with warnings.catch_warnings():
+            warnings.filterwarnings("ignore", category=KwantDeprecationWarning)
+            syst.hamiltonian_submatrix(params=dict(p1=2))
 
     # test that passing parameters without default values works, and that
     # passing parameters with default values fails