Two questions get conflated in every VPN billing discussion: was this user allowed to connect, and what did they actually do. The first is answered by authentication. The second requires accounting records that begin, update and end. A login that succeeds proves the first and says nothing about the second, which is why a working RADIUS authentication setup can still produce an empty usage report.

Two different questions

Authentication decides whether a connection may begin, and it returns a verdict plus attributes such as an address pool or a group. Accounting records the service that followed, as a sequence of events tied to one session.

They travel over the same protocol and usually to the same server, which is exactly why people assume one implies the other.

Nothing in an access request carries the session's duration, and nothing in a Stop record re-decides whether the user should have been admitted. Treating them as separate contracts makes the integration work visible: one path needs a decision, the other needs a lifecycle with a beginning, a middle and an end.

What the three record types give you

A Start record opens a session, an Interim-Update reports activity while it is open, and a Stop closes it. All three carry a session identifier so the receiver can relate them to one service event.

That identifier is the only reliable link between them, because the same username may hold several sessions in sequence or in parallel. Design your storage around it rather than around the account name.

Acknowledging a record is a separate matter from storing it well. The accounting specification forbids the acknowledgement when the record could not be written, so a response does tell you the receiver accepted responsibility. It does not tell you that the later reporting job, the dashboard or the billing export consumed it correctly.

Why the username is not the session

One person connects from a laptop in the morning and a phone in the afternoon, and both sessions carry the same account name. A Start that arrives without its matching Stop cannot be closed by looking up the name and picking the oldest open row.

That shortcut is how usage reports acquire impossible durations.

Keep the network access server identity alongside the session identifier, because two servers can assign the same value in different contexts and a merge on the identifier alone can join unrelated sessions. When a session ends ungracefully, the reconciliation policy has to decide how to close it, and that decision belongs in the design rather than in a manual database edit made once a month.

Where PAM fits and where it does not

OpenVPN's authentication plugin calls PAM's authentication and account-management stages. The account stage checks eligibility; its name does not mean usage accounting, and the plugin does not drive PAM's session open and close hooks.

Some PAM RADIUS modules can send accounting records through those session hooks, and that works only when the application actually invokes them.

Adding such a module to an authentication stack therefore does not create disconnect events. If you need the full lifecycle, choose an integration that owns it: a plugin or a supported build that emits Start, Interim-Update and Stop as the connection changes state. Check its maintenance status and its documented behaviour when the receiver is unavailable, because a plugin that drops records silently looks identical to one that never sent them. The accounting specification defines the record semantics the integration has to honour.

An acceptance run that proves the contract

Test a normal connect and disconnect, then a reconnect under the same account, then a client that disappears without disconnecting.

Follow one session identifier from generation through acknowledgement to storage, and check the counters' direction, units and interface. An unlabeled byte count is impossible to audit later.

Finally, confirm that a session the server had to time out is represented in a way the report understands. A contract that only covers graceful disconnects is a contract that fails on the days you need it most.

អត្ថបទពាក់ព័ន្ធ