Replication is not "copy the data to another machine." The primary doesn't re-run queries and it doesn't ship table files — it ships the log, and the replica replays it. Everything about replication, including lag, follows from that.
Postgres ships the WAL itself: the primary streams the same log segments that power crash recovery to standby nodes, which replay them and apply pages — physical replication. MySQL ships the binlog instead: the primary writes logical records of what happened (row-level: "this row changed to these values"; older statement-level: "run this SQL"), and replicas apply those records to their own storage — logical replication. Physical is simpler and byte-faithful — the standby is a point-in-time copy of the primary's files. Logical can replicate across versions and even between engines, and it's what powers change data capture, but it's slower to apply because each record is a mini transaction on the replica.
Lag is the time between a transaction committing on the primary and its effects landing on a replica — the moment when the two nodes disagree. The mechanisms: the WAL must be shipped over the network; the replica must write it to its own disk and then apply it. The apply step is the usual bottleneck — historically replicas applied single-threaded (MySQL pre-8.0 parallel appliers are the famous case), so a primary with high write concurrency generates apply work faster than one thread can consume it, and lag grows without bound until the workload drops. Long-running transactions on the primary, huge DDL, and replicas busy serving their own reads all add to it. Lag of seconds to minutes under load is normal; the question is whether your application can tolerate it.
The consequences are the part interviews probe. Asynchronous replication means a replica can answer a read with data the primary no longer has — the classic failure is reading from a replica right after writing to the primary and seeing the old value (read-your-writes violation), or doing an "increment then read" flow and getting a stale count. Failover is where lag becomes data loss: the last transactions committed on the primary but not yet applied to the replica vanish if the primary dies.
The controls: synchronous replication makes the primary's COMMIT wait until the replica acknowledges the WAL — zero loss, but commit latency rises to replica round-trip time and availability drops with it. For reads, you route: session pinning (send a client's reads to the primary for a grace period after writes), monotonic reads on a single replica, or read-after-write verification. The answer that lands: lag isn't a bug, it's a physical consequence of asynchronous transport, and the design job is choosing what consistency each read path needs.