diff --git a/docs/python-api.rst b/docs/python-api.rst
index 9d272c3..997bd97 100644
--- a/docs/python-api.rst
+++ b/docs/python-api.rst
@@ -868,6 +868,17 @@ The ``.indexes`` property shows you all indexes created for a table. It is not a
      Index(seq=4, name='"Street_Tree_List_qCaretaker"', unique=0, origin='c', partial=0, columns=['qCaretaker']),
      Index(seq=5, name='"Street_Tree_List_PlantType"', unique=0, origin='c', partial=0, columns=['PlantType'])]
 
+The ``.triggers`` property lists database triggers. It can be used on both database and table objects.
+
+::
+
+    >>> db["authors"].triggers
+    [Trigger(name='authors_ai', table='authors', sql='CREATE TRIGGER [authors_ai] AFTER INSERT...'),
+     Trigger(name='authors_ad', table='authors', sql="CREATE TRIGGER [authors_ad] AFTER DELETE..."),
+     Trigger(name='authors_au', table='authors', sql="CREATE TRIGGER [authors_au] AFTER UPDATE")]
+    >>> db.triggers
+    ... similar output to db["authors"].triggers
+
 Enabling full-text search
 =========================
 
diff --git a/sqlite_utils/db.py b/sqlite_utils/db.py
index b7837c7..e36e191 100644
--- a/sqlite_utils/db.py
+++ b/sqlite_utils/db.py
@@ -20,6 +20,9 @@ ForeignKey = namedtuple(
     "ForeignKey", ("table", "column", "other_table", "other_column")
 )
 Index = namedtuple("Index", ("seq", "name", "unique", "origin", "partial", "columns"))
+Trigger = namedtuple("Trigger", ("name", "table", "sql"))
+
+
 DEFAULT = object()
 
 COLUMN_TYPE_MAPPING = {
@@ -146,6 +149,15 @@ class Database:
     def views(self):
         return [self[name] for name in self.view_names()]
 
+    @property
+    def triggers(self):
+        return [
+            Trigger(*r)
+            for r in self.conn.execute(
+                "select name, tbl_name, sql from sqlite_master where type = 'trigger'"
+            ).fetchall()
+        ]
+
     def execute_returning_dicts(self, sql, params=None):
         cursor = self.conn.execute(sql, params or tuple())
         keys = [d[0] for d in cursor.description]
@@ -561,6 +573,17 @@ class Table(Queryable):
             indexes.append(Index(**row))
         return indexes
 
+    @property
+    def triggers(self):
+        return [
+            Trigger(*r)
+            for r in self.db.conn.execute(
+                "select name, tbl_name, sql from sqlite_master where type = 'trigger'"
+                " and tbl_name = ?",
+                (self.name,),
+            ).fetchall()
+        ]
+
     def create(
         self,
         columns,

Ability to introspect triggers
Now that we're creating triggers (thanks to @amjith in #57) it would be neat if we could introspect them too.

I'm thinking:

`db.triggers` - lists all triggers for the database
`db["tablename"].triggers` - lists triggers for that database

The underlying query for this is `select * from sqlite_master where type = 'trigger'`

I'll return the trigger information in a new namedtuple, similar to how Indexes and ForeignKeys work.
diff --git a/tests/test_introspect.py b/tests/test_introspect.py
index b04af6d..7c01a0b 100644
--- a/tests/test_introspect.py
+++ b/tests/test_introspect.py
@@ -121,3 +121,30 @@ def test_guess_foreign_table(fresh_db, column, expected_table_guess):
 def test_pks(fresh_db, pk, expected):
     fresh_db["foo"].insert_all([{"id": 1, "id2": 2}], pk=pk)
     assert expected == fresh_db["foo"].pks
+
+
+def test_triggers(fresh_db):
+    assert [] == fresh_db.triggers
+    authors = fresh_db["authors"]
+    authors.insert_all(
+        [
+            {"name": "Frank Herbert", "famous_works": "Dune"},
+            {"name": "Neal Stephenson", "famous_works": "Cryptonomicon"},
+        ]
+    )
+    fresh_db["other"].insert({"foo": "bar"})
+    assert [] == authors.triggers
+    assert [] == fresh_db["other"].triggers
+    authors.enable_fts(
+        ["name", "famous_works"], fts_version="FTS4", create_triggers=True
+    )
+    expected_triggers = {
+        ("authors_ai", "authors"),
+        ("authors_ad", "authors"),
+        ("authors_au", "authors"),
+    }
+    assert expected_triggers == {(t.name, t.table) for t in fresh_db.triggers}
+    assert expected_triggers == {
+        (t.name, t.table) for t in fresh_db["authors"].triggers
+    }
+    assert [] == fresh_db["other"].triggers

pip install -e .[dev]
parse_log_pytest
requirements.txt
apt-get update apt-get install -y gcc sqlite3
3.7
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
certifi @ file:///croot/certifi_1671487769961/work/certifi
click==8.1.8
click-default-group==1.2.4
importlib-metadata==6.7.0
-e git+https://github.com/simonw/sqlite-utils.git@405e092d5916e70df10f82d15e9c052aa9ee8d80#egg=sqlite_utils
tabulate==0.9.0
typing_extensions==4.7.1
zipp==3.15.0

name: sqlite-utils
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=22.3.1=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - click==8.1.8
      - click-default-group==1.2.4
      - importlib-metadata==6.7.0
      - tabulate==0.9.0
      - typing-extensions==4.7.1
      - zipp==3.15.0
prefix: /opt/conda/envs/sqlite-utils

tests/test_introspect.py::test_triggers
tests/test_introspect.py::test_table_names tests/test_introspect.py::test_view_names tests/test_introspect.py::test_table_names_fts4 tests/test_introspect.py::test_detect_fts tests/test_introspect.py::test_tables tests/test_introspect.py::test_views tests/test_introspect.py::test_count tests/test_introspect.py::test_columns tests/test_introspect.py::test_rows tests/test_introspect.py::test_schema tests/test_introspect.py::test_table_repr tests/test_introspect.py::test_indexes tests/test_introspect.py::test_guess_foreign_table[author-authors] tests/test_introspect.py::test_guess_foreign_table[author_id-authors] tests/test_introspect.py::test_guess_foreign_table[authors-authors] tests/test_introspect.py::test_guess_foreign_table[genre-genre] tests/test_introspect.py::test_guess_foreign_table[genre_id-genre] tests/test_introspect.py::test_pks[None-expected0] tests/test_introspect.py::test_pks[id-expected1] tests/test_introspect.py::test_pks[pk2-expected2]
sqlite_utils/db.py docs/python-api.rst
sqlite_utils/db.py docs/python-api.rst