What does ON DELETE CASCADE do, and when is it right versus dangerous?
ON DELETE CASCADE says that when a parent row is deleted, every child row that references it should be deleted too. The engine does it as part of the same statement, inside the same transaction, so you never end up with orphans even for a moment.
The other referential actions are worth knowing side by side, because the difference between them is a business decision rather than a technical one. RESTRICT is the default: the delete is refused while children still point at the parent. NO ACTION behaves the same but is checked at the end of the statement rather than immediately, which matters if you delete and re-insert a parent within one transaction. SET NULL sets the child's foreign key to NULL, keeping the child but orphaning it — which only works when the column is nullable. SET DEFAULT sets the column to its declared default, which is rarely what anyone actually wants.
CASCADE is right when the child has no meaning without the parent. An order line cannot exist without its order. A book-author link cannot exist without both of them. A review of a deleted product is meaningless, so deleting it is reasonable. In all of those cases the child is a component of the parent, and keeping it would leave the database in a state the business cannot describe.
CASCADE is dangerous when the child is more valuable than the parent, or when the relationship is a reference rather than an ownership. Deleting a customer should not silently delete their order history, their invoices or their support tickets — those are records you need for accounting, for dispute resolution and for regulatory reasons. In that situation you want the delete to be refused so a human decides, or a soft delete so the record survives.
Two practical warnings. A cascade can cascade further: if a third table references the child table, deleting the original parent can remove a whole subtree, and the number of rows affected can be far larger than the statement suggests. And cascades fire the child's delete triggers, so a trigger that writes an audit row will produce one audit row per deleted child — which is usually correct, and occasionally a surprise.